Merge "BanTargetApiAnnotation check now actually looks for the annotation and not usages of methods annotated by it." into androidx-master-dev
diff --git a/activity/activity-ktx/api/1.2.0-beta01.txt b/activity/activity-ktx/api/1.2.0-beta01.txt
new file mode 100644
index 0000000..ec6569a
--- /dev/null
+++ b/activity/activity-ktx/api/1.2.0-beta01.txt
@@ -0,0 +1,40 @@
+// Signature format: 3.0
+package androidx.activity {
+
+ public final class ActivityViewModelLazyKt {
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! viewModels(androidx.activity.ComponentActivity, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+ }
+
+ public final class OnBackPressedDispatcherKt {
+ method public static androidx.activity.OnBackPressedCallback addCallback(androidx.activity.OnBackPressedDispatcher, androidx.lifecycle.LifecycleOwner? owner = null, boolean enabled = true, kotlin.jvm.functions.Function1<? super androidx.activity.OnBackPressedCallback,kotlin.Unit> onBackPressed);
+ }
+
+}
+
+package androidx.activity.contextaware {
+
+ public final class ContextAwareKt {
+ method public static suspend inline <R> Object? withContextAvailable(androidx.activity.contextaware.ContextAware, kotlin.jvm.functions.Function1<? super android.content.Context,? extends R> onContextAvailable, kotlin.coroutines.Continuation<? super R> p);
+ }
+
+}
+
+package androidx.activity.result {
+
+ public final class ActivityResultCallerKt {
+ method public static <I, O> androidx.activity.result.ActivityResultLauncher<kotlin.Unit> registerForActivityResult(androidx.activity.result.ActivityResultCaller, androidx.activity.result.contract.ActivityResultContract<I,O> contract, I? input, androidx.activity.result.ActivityResultRegistry registry, kotlin.jvm.functions.Function1<? super O,kotlin.Unit> callback);
+ method public static <I, O> androidx.activity.result.ActivityResultLauncher<kotlin.Unit> registerForActivityResult(androidx.activity.result.ActivityResultCaller, androidx.activity.result.contract.ActivityResultContract<I,O> contract, I? input, kotlin.jvm.functions.Function1<? super O,kotlin.Unit> callback);
+ }
+
+ public final class ActivityResultKt {
+ method public static operator int component1(androidx.activity.result.ActivityResult);
+ method public static operator android.content.Intent? component2(androidx.activity.result.ActivityResult);
+ }
+
+ public final class ActivityResultLauncherKt {
+ method public static void launch(androidx.activity.result.ActivityResultLauncher<java.lang.Void>, androidx.core.app.ActivityOptionsCompat? options = null);
+ method public static void launchUnit(androidx.activity.result.ActivityResultLauncher<kotlin.Unit>, androidx.core.app.ActivityOptionsCompat? options = null);
+ }
+
+}
+
diff --git a/activity/activity-ktx/api/public_plus_experimental_1.2.0-beta01.txt b/activity/activity-ktx/api/public_plus_experimental_1.2.0-beta01.txt
new file mode 100644
index 0000000..ec6569a
--- /dev/null
+++ b/activity/activity-ktx/api/public_plus_experimental_1.2.0-beta01.txt
@@ -0,0 +1,40 @@
+// Signature format: 3.0
+package androidx.activity {
+
+ public final class ActivityViewModelLazyKt {
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! viewModels(androidx.activity.ComponentActivity, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+ }
+
+ public final class OnBackPressedDispatcherKt {
+ method public static androidx.activity.OnBackPressedCallback addCallback(androidx.activity.OnBackPressedDispatcher, androidx.lifecycle.LifecycleOwner? owner = null, boolean enabled = true, kotlin.jvm.functions.Function1<? super androidx.activity.OnBackPressedCallback,kotlin.Unit> onBackPressed);
+ }
+
+}
+
+package androidx.activity.contextaware {
+
+ public final class ContextAwareKt {
+ method public static suspend inline <R> Object? withContextAvailable(androidx.activity.contextaware.ContextAware, kotlin.jvm.functions.Function1<? super android.content.Context,? extends R> onContextAvailable, kotlin.coroutines.Continuation<? super R> p);
+ }
+
+}
+
+package androidx.activity.result {
+
+ public final class ActivityResultCallerKt {
+ method public static <I, O> androidx.activity.result.ActivityResultLauncher<kotlin.Unit> registerForActivityResult(androidx.activity.result.ActivityResultCaller, androidx.activity.result.contract.ActivityResultContract<I,O> contract, I? input, androidx.activity.result.ActivityResultRegistry registry, kotlin.jvm.functions.Function1<? super O,kotlin.Unit> callback);
+ method public static <I, O> androidx.activity.result.ActivityResultLauncher<kotlin.Unit> registerForActivityResult(androidx.activity.result.ActivityResultCaller, androidx.activity.result.contract.ActivityResultContract<I,O> contract, I? input, kotlin.jvm.functions.Function1<? super O,kotlin.Unit> callback);
+ }
+
+ public final class ActivityResultKt {
+ method public static operator int component1(androidx.activity.result.ActivityResult);
+ method public static operator android.content.Intent? component2(androidx.activity.result.ActivityResult);
+ }
+
+ public final class ActivityResultLauncherKt {
+ method public static void launch(androidx.activity.result.ActivityResultLauncher<java.lang.Void>, androidx.core.app.ActivityOptionsCompat? options = null);
+ method public static void launchUnit(androidx.activity.result.ActivityResultLauncher<kotlin.Unit>, androidx.core.app.ActivityOptionsCompat? options = null);
+ }
+
+}
+
diff --git a/activity/activity-ktx/api/res-1.2.0-beta01.txt b/activity/activity-ktx/api/res-1.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/activity/activity-ktx/api/res-1.2.0-beta01.txt
diff --git a/activity/activity-ktx/api/restricted_1.2.0-beta01.txt b/activity/activity-ktx/api/restricted_1.2.0-beta01.txt
new file mode 100644
index 0000000..ec6569a
--- /dev/null
+++ b/activity/activity-ktx/api/restricted_1.2.0-beta01.txt
@@ -0,0 +1,40 @@
+// Signature format: 3.0
+package androidx.activity {
+
+ public final class ActivityViewModelLazyKt {
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! viewModels(androidx.activity.ComponentActivity, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+ }
+
+ public final class OnBackPressedDispatcherKt {
+ method public static androidx.activity.OnBackPressedCallback addCallback(androidx.activity.OnBackPressedDispatcher, androidx.lifecycle.LifecycleOwner? owner = null, boolean enabled = true, kotlin.jvm.functions.Function1<? super androidx.activity.OnBackPressedCallback,kotlin.Unit> onBackPressed);
+ }
+
+}
+
+package androidx.activity.contextaware {
+
+ public final class ContextAwareKt {
+ method public static suspend inline <R> Object? withContextAvailable(androidx.activity.contextaware.ContextAware, kotlin.jvm.functions.Function1<? super android.content.Context,? extends R> onContextAvailable, kotlin.coroutines.Continuation<? super R> p);
+ }
+
+}
+
+package androidx.activity.result {
+
+ public final class ActivityResultCallerKt {
+ method public static <I, O> androidx.activity.result.ActivityResultLauncher<kotlin.Unit> registerForActivityResult(androidx.activity.result.ActivityResultCaller, androidx.activity.result.contract.ActivityResultContract<I,O> contract, I? input, androidx.activity.result.ActivityResultRegistry registry, kotlin.jvm.functions.Function1<? super O,kotlin.Unit> callback);
+ method public static <I, O> androidx.activity.result.ActivityResultLauncher<kotlin.Unit> registerForActivityResult(androidx.activity.result.ActivityResultCaller, androidx.activity.result.contract.ActivityResultContract<I,O> contract, I? input, kotlin.jvm.functions.Function1<? super O,kotlin.Unit> callback);
+ }
+
+ public final class ActivityResultKt {
+ method public static operator int component1(androidx.activity.result.ActivityResult);
+ method public static operator android.content.Intent? component2(androidx.activity.result.ActivityResult);
+ }
+
+ public final class ActivityResultLauncherKt {
+ method public static void launch(androidx.activity.result.ActivityResultLauncher<java.lang.Void>, androidx.core.app.ActivityOptionsCompat? options = null);
+ method public static void launchUnit(androidx.activity.result.ActivityResultLauncher<kotlin.Unit>, androidx.core.app.ActivityOptionsCompat? options = null);
+ }
+
+}
+
diff --git a/activity/activity/api/1.2.0-beta01.txt b/activity/activity/api/1.2.0-beta01.txt
new file mode 100644
index 0000000..4e9dd74
--- /dev/null
+++ b/activity/activity/api/1.2.0-beta01.txt
@@ -0,0 +1,259 @@
+// Signature format: 3.0
+package androidx.activity {
+
+ public class ComponentActivity extends android.app.Activity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.activity.contextaware.ContextAware androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+ ctor public ComponentActivity();
+ ctor @ContentView public ComponentActivity(@LayoutRes int);
+ method public final void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public final androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
+ method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+ method @Deprecated public Object? getLastCustomNonConfigurationInstance();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method public final androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+ method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+ method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ method @Deprecated @CallSuper protected void onActivityResult(int, int, android.content.Intent?);
+ method @Deprecated @CallSuper public void onRequestPermissionsResult(int, String![], int[]);
+ method @Deprecated public Object? onRetainCustomNonConfigurationInstance();
+ method public final Object? onRetainNonConfigurationInstance();
+ method public android.content.Context? peekAvailableContext();
+ method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method @Deprecated public void startActivityForResult(android.content.Intent!, int);
+ method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int) throws android.content.IntentSender.SendIntentException;
+ method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ }
+
+ public abstract class OnBackPressedCallback {
+ ctor public OnBackPressedCallback(boolean);
+ method @MainThread public abstract void handleOnBackPressed();
+ method @MainThread public final boolean isEnabled();
+ method @MainThread public final void remove();
+ method @MainThread public final void setEnabled(boolean);
+ }
+
+ public final class OnBackPressedDispatcher {
+ ctor public OnBackPressedDispatcher();
+ ctor public OnBackPressedDispatcher(Runnable?);
+ method @MainThread public void addCallback(androidx.activity.OnBackPressedCallback);
+ method @MainThread public void addCallback(androidx.lifecycle.LifecycleOwner, androidx.activity.OnBackPressedCallback);
+ method @MainThread public boolean hasEnabledCallbacks();
+ method @MainThread public void onBackPressed();
+ }
+
+ public interface OnBackPressedDispatcherOwner extends androidx.lifecycle.LifecycleOwner {
+ method public androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+ }
+
+}
+
+package androidx.activity.contextaware {
+
+ public interface ContextAware {
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public android.content.Context? peekAvailableContext();
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public final class ContextAwareHelper {
+ ctor public ContextAwareHelper();
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void clearAvailableContext();
+ method public void dispatchOnContextAvailable(android.content.Context);
+ method public android.content.Context? peekAvailableContext();
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public interface OnContextAvailableListener {
+ method public void onContextAvailable(android.content.Context);
+ }
+
+}
+
+package androidx.activity.result {
+
+ public final class ActivityResult implements android.os.Parcelable {
+ ctor public ActivityResult(int, android.content.Intent?);
+ method public int describeContents();
+ method public android.content.Intent? getData();
+ method public int getResultCode();
+ method public static String resultCodeToString(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<androidx.activity.result.ActivityResult!> CREATOR;
+ }
+
+ public interface ActivityResultCallback<O> {
+ method public void onActivityResult(O!);
+ }
+
+ public interface ActivityResultCaller {
+ method public <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+ }
+
+ public abstract class ActivityResultLauncher<I> {
+ ctor public ActivityResultLauncher();
+ method public abstract androidx.activity.result.contract.ActivityResultContract<I!,?> getContract();
+ method public void launch(I!);
+ method public abstract void launch(I!, androidx.core.app.ActivityOptionsCompat?);
+ method @MainThread public abstract void unregister();
+ }
+
+ public abstract class ActivityResultRegistry {
+ ctor public ActivityResultRegistry();
+ method @MainThread public final boolean dispatchResult(int, int, android.content.Intent?);
+ method @MainThread public final <O> boolean dispatchResult(int, O!);
+ method @MainThread public abstract <I, O> void onLaunch(int, androidx.activity.result.contract.ActivityResultContract<I!,O!>, I!, androidx.core.app.ActivityOptionsCompat?);
+ method public final void onRestoreInstanceState(android.os.Bundle?);
+ method public final void onSaveInstanceState(android.os.Bundle);
+ method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> register(String, androidx.lifecycle.LifecycleOwner, androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> register(String, androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ }
+
+ public interface ActivityResultRegistryOwner {
+ method public androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
+ }
+
+ public final class IntentSenderRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.content.Intent? getFillInIntent();
+ method public int getFlagsMask();
+ method public int getFlagsValues();
+ method public android.content.IntentSender getIntentSender();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<androidx.activity.result.IntentSenderRequest!> CREATOR;
+ }
+
+ public static final class IntentSenderRequest.Builder {
+ ctor public IntentSenderRequest.Builder(android.content.IntentSender);
+ ctor public IntentSenderRequest.Builder(android.app.PendingIntent);
+ method public androidx.activity.result.IntentSenderRequest build();
+ method public androidx.activity.result.IntentSenderRequest.Builder setFillInIntent(android.content.Intent?);
+ method public androidx.activity.result.IntentSenderRequest.Builder setFlags(int, int);
+ }
+
+}
+
+package androidx.activity.result.contract {
+
+ public abstract class ActivityResultContract<I, O> {
+ ctor public ActivityResultContract();
+ method public abstract android.content.Intent createIntent(android.content.Context, I!);
+ method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<O!>? getSynchronousResult(android.content.Context, I!);
+ method public abstract O! parseResult(int, android.content.Intent?);
+ }
+
+ public static final class ActivityResultContract.SynchronousResult<T> {
+ ctor public ActivityResultContract.SynchronousResult(T!);
+ method public T! getValue();
+ }
+
+ public final class ActivityResultContracts {
+ }
+
+ public static class ActivityResultContracts.CreateDocument extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,android.net.Uri> {
+ ctor public ActivityResultContracts.CreateDocument();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String);
+ method public final android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.GetContent extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,android.net.Uri> {
+ ctor public ActivityResultContracts.GetContent();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String);
+ method public final android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.GetMultipleContents extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,java.util.List<android.net.Uri>> {
+ ctor public ActivityResultContracts.GetMultipleContents();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.List<android.net.Uri!>!>? getSynchronousResult(android.content.Context, String);
+ method public final java.util.List<android.net.Uri!> parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.OpenDocument extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],android.net.Uri> {
+ ctor public ActivityResultContracts.OpenDocument();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String![]);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String![]);
+ method public final android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.OpenDocumentTree extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,android.net.Uri> {
+ ctor public ActivityResultContracts.OpenDocumentTree();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri?);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, android.net.Uri?);
+ method public final android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.OpenMultipleDocuments extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],java.util.List<android.net.Uri>> {
+ ctor public ActivityResultContracts.OpenMultipleDocuments();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String![]);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.List<android.net.Uri!>!>? getSynchronousResult(android.content.Context, String![]);
+ method public final java.util.List<android.net.Uri!> parseResult(int, android.content.Intent?);
+ }
+
+ public static final class ActivityResultContracts.PickContact extends androidx.activity.result.contract.ActivityResultContract<java.lang.Void,android.net.Uri> {
+ ctor public ActivityResultContracts.PickContact();
+ method public android.content.Intent createIntent(android.content.Context, Void?);
+ method public android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static final class ActivityResultContracts.RequestMultiplePermissions extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],java.util.Map<java.lang.String,java.lang.Boolean>> {
+ ctor public ActivityResultContracts.RequestMultiplePermissions();
+ method public android.content.Intent createIntent(android.content.Context, String![]);
+ method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.Map<java.lang.String!,java.lang.Boolean!>!>? getSynchronousResult(android.content.Context, String![]?);
+ method public java.util.Map<java.lang.String!,java.lang.Boolean!> parseResult(int, android.content.Intent?);
+ field public static final String ACTION_REQUEST_PERMISSIONS = "androidx.activity.result.contract.action.REQUEST_PERMISSIONS";
+ field public static final String EXTRA_PERMISSIONS = "androidx.activity.result.contract.extra.PERMISSIONS";
+ field public static final String EXTRA_PERMISSION_GRANT_RESULTS = "androidx.activity.result.contract.extra.PERMISSION_GRANT_RESULTS";
+ }
+
+ public static final class ActivityResultContracts.RequestPermission extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,java.lang.Boolean> {
+ ctor public ActivityResultContracts.RequestPermission();
+ method public android.content.Intent createIntent(android.content.Context, String);
+ method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.lang.Boolean!>? getSynchronousResult(android.content.Context, String?);
+ method public Boolean parseResult(int, android.content.Intent?);
+ }
+
+ public static final class ActivityResultContracts.StartActivityForResult extends androidx.activity.result.contract.ActivityResultContract<android.content.Intent,androidx.activity.result.ActivityResult> {
+ ctor public ActivityResultContracts.StartActivityForResult();
+ method public android.content.Intent createIntent(android.content.Context, android.content.Intent);
+ method public androidx.activity.result.ActivityResult parseResult(int, android.content.Intent?);
+ field public static final String EXTRA_ACTIVITY_OPTIONS_BUNDLE = "androidx.activity.result.contract.extra.ACTIVITY_OPTIONS_BUNDLE";
+ }
+
+ public static final class ActivityResultContracts.StartIntentSenderForResult extends androidx.activity.result.contract.ActivityResultContract<androidx.activity.result.IntentSenderRequest,androidx.activity.result.ActivityResult> {
+ ctor public ActivityResultContracts.StartIntentSenderForResult();
+ method public android.content.Intent createIntent(android.content.Context, androidx.activity.result.IntentSenderRequest);
+ method public androidx.activity.result.ActivityResult parseResult(int, android.content.Intent?);
+ field public static final String ACTION_INTENT_SENDER_REQUEST = "androidx.activity.result.contract.action.INTENT_SENDER_REQUEST";
+ field public static final String EXTRA_INTENT_SENDER_REQUEST = "androidx.activity.result.contract.extra.INTENT_SENDER_REQUEST";
+ field public static final String EXTRA_SEND_INTENT_EXCEPTION = "androidx.activity.result.contract.extra.SEND_INTENT_EXCEPTION";
+ }
+
+ public static class ActivityResultContracts.TakePicture extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,java.lang.Boolean> {
+ ctor public ActivityResultContracts.TakePicture();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.lang.Boolean!>? getSynchronousResult(android.content.Context, android.net.Uri);
+ method public final Boolean parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.TakePicturePreview extends androidx.activity.result.contract.ActivityResultContract<java.lang.Void,android.graphics.Bitmap> {
+ ctor public ActivityResultContracts.TakePicturePreview();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, Void?);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.graphics.Bitmap!>? getSynchronousResult(android.content.Context, Void?);
+ method public final android.graphics.Bitmap? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.TakeVideo extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,android.graphics.Bitmap> {
+ ctor public ActivityResultContracts.TakeVideo();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.graphics.Bitmap!>? getSynchronousResult(android.content.Context, android.net.Uri);
+ method public final android.graphics.Bitmap? parseResult(int, android.content.Intent?);
+ }
+
+}
+
diff --git a/activity/activity/api/public_plus_experimental_1.2.0-beta01.txt b/activity/activity/api/public_plus_experimental_1.2.0-beta01.txt
new file mode 100644
index 0000000..823a4ed
--- /dev/null
+++ b/activity/activity/api/public_plus_experimental_1.2.0-beta01.txt
@@ -0,0 +1,258 @@
+// Signature format: 3.0
+package androidx.activity {
+
+ public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.activity.contextaware.ContextAware androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+ ctor public ComponentActivity();
+ ctor @ContentView public ComponentActivity(@LayoutRes int);
+ method public final void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public final androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
+ method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+ method @Deprecated public Object? getLastCustomNonConfigurationInstance();
+ method public final androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+ method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+ method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ method @Deprecated @CallSuper protected void onActivityResult(int, int, android.content.Intent?);
+ method @Deprecated @CallSuper public void onRequestPermissionsResult(int, String![], int[]);
+ method @Deprecated public Object? onRetainCustomNonConfigurationInstance();
+ method public final Object? onRetainNonConfigurationInstance();
+ method public android.content.Context? peekAvailableContext();
+ method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method @Deprecated public void startActivityForResult(android.content.Intent!, int);
+ method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int) throws android.content.IntentSender.SendIntentException;
+ method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ }
+
+ public abstract class OnBackPressedCallback {
+ ctor public OnBackPressedCallback(boolean);
+ method @MainThread public abstract void handleOnBackPressed();
+ method @MainThread public final boolean isEnabled();
+ method @MainThread public final void remove();
+ method @MainThread public final void setEnabled(boolean);
+ }
+
+ public final class OnBackPressedDispatcher {
+ ctor public OnBackPressedDispatcher();
+ ctor public OnBackPressedDispatcher(Runnable?);
+ method @MainThread public void addCallback(androidx.activity.OnBackPressedCallback);
+ method @MainThread public void addCallback(androidx.lifecycle.LifecycleOwner, androidx.activity.OnBackPressedCallback);
+ method @MainThread public boolean hasEnabledCallbacks();
+ method @MainThread public void onBackPressed();
+ }
+
+ public interface OnBackPressedDispatcherOwner extends androidx.lifecycle.LifecycleOwner {
+ method public androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+ }
+
+}
+
+package androidx.activity.contextaware {
+
+ public interface ContextAware {
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public android.content.Context? peekAvailableContext();
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public final class ContextAwareHelper {
+ ctor public ContextAwareHelper();
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void clearAvailableContext();
+ method public void dispatchOnContextAvailable(android.content.Context);
+ method public android.content.Context? peekAvailableContext();
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public interface OnContextAvailableListener {
+ method public void onContextAvailable(android.content.Context);
+ }
+
+}
+
+package androidx.activity.result {
+
+ public final class ActivityResult implements android.os.Parcelable {
+ ctor public ActivityResult(int, android.content.Intent?);
+ method public int describeContents();
+ method public android.content.Intent? getData();
+ method public int getResultCode();
+ method public static String resultCodeToString(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<androidx.activity.result.ActivityResult!> CREATOR;
+ }
+
+ public interface ActivityResultCallback<O> {
+ method public void onActivityResult(O!);
+ }
+
+ public interface ActivityResultCaller {
+ method public <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+ }
+
+ public abstract class ActivityResultLauncher<I> {
+ ctor public ActivityResultLauncher();
+ method public abstract androidx.activity.result.contract.ActivityResultContract<I!,?> getContract();
+ method public void launch(I!);
+ method public abstract void launch(I!, androidx.core.app.ActivityOptionsCompat?);
+ method @MainThread public abstract void unregister();
+ }
+
+ public abstract class ActivityResultRegistry {
+ ctor public ActivityResultRegistry();
+ method @MainThread public final boolean dispatchResult(int, int, android.content.Intent?);
+ method @MainThread public final <O> boolean dispatchResult(int, O!);
+ method @MainThread public abstract <I, O> void onLaunch(int, androidx.activity.result.contract.ActivityResultContract<I!,O!>, I!, androidx.core.app.ActivityOptionsCompat?);
+ method public final void onRestoreInstanceState(android.os.Bundle?);
+ method public final void onSaveInstanceState(android.os.Bundle);
+ method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> register(String, androidx.lifecycle.LifecycleOwner, androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> register(String, androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ }
+
+ public interface ActivityResultRegistryOwner {
+ method public androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
+ }
+
+ public final class IntentSenderRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.content.Intent? getFillInIntent();
+ method public int getFlagsMask();
+ method public int getFlagsValues();
+ method public android.content.IntentSender getIntentSender();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<androidx.activity.result.IntentSenderRequest!> CREATOR;
+ }
+
+ public static final class IntentSenderRequest.Builder {
+ ctor public IntentSenderRequest.Builder(android.content.IntentSender);
+ ctor public IntentSenderRequest.Builder(android.app.PendingIntent);
+ method public androidx.activity.result.IntentSenderRequest build();
+ method public androidx.activity.result.IntentSenderRequest.Builder setFillInIntent(android.content.Intent?);
+ method public androidx.activity.result.IntentSenderRequest.Builder setFlags(int, int);
+ }
+
+}
+
+package androidx.activity.result.contract {
+
+ public abstract class ActivityResultContract<I, O> {
+ ctor public ActivityResultContract();
+ method public abstract android.content.Intent createIntent(android.content.Context, I!);
+ method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<O!>? getSynchronousResult(android.content.Context, I!);
+ method public abstract O! parseResult(int, android.content.Intent?);
+ }
+
+ public static final class ActivityResultContract.SynchronousResult<T> {
+ ctor public ActivityResultContract.SynchronousResult(T!);
+ method public T! getValue();
+ }
+
+ public final class ActivityResultContracts {
+ }
+
+ public static class ActivityResultContracts.CreateDocument extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,android.net.Uri> {
+ ctor public ActivityResultContracts.CreateDocument();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String);
+ method public final android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.GetContent extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,android.net.Uri> {
+ ctor public ActivityResultContracts.GetContent();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String);
+ method public final android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.GetMultipleContents extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,java.util.List<android.net.Uri>> {
+ ctor public ActivityResultContracts.GetMultipleContents();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.List<android.net.Uri!>!>? getSynchronousResult(android.content.Context, String);
+ method public final java.util.List<android.net.Uri!> parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.OpenDocument extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],android.net.Uri> {
+ ctor public ActivityResultContracts.OpenDocument();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String![]);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String![]);
+ method public final android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.OpenDocumentTree extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,android.net.Uri> {
+ ctor public ActivityResultContracts.OpenDocumentTree();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri?);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, android.net.Uri?);
+ method public final android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.OpenMultipleDocuments extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],java.util.List<android.net.Uri>> {
+ ctor public ActivityResultContracts.OpenMultipleDocuments();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String![]);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.List<android.net.Uri!>!>? getSynchronousResult(android.content.Context, String![]);
+ method public final java.util.List<android.net.Uri!> parseResult(int, android.content.Intent?);
+ }
+
+ public static final class ActivityResultContracts.PickContact extends androidx.activity.result.contract.ActivityResultContract<java.lang.Void,android.net.Uri> {
+ ctor public ActivityResultContracts.PickContact();
+ method public android.content.Intent createIntent(android.content.Context, Void?);
+ method public android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static final class ActivityResultContracts.RequestMultiplePermissions extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],java.util.Map<java.lang.String,java.lang.Boolean>> {
+ ctor public ActivityResultContracts.RequestMultiplePermissions();
+ method public android.content.Intent createIntent(android.content.Context, String![]);
+ method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.Map<java.lang.String!,java.lang.Boolean!>!>? getSynchronousResult(android.content.Context, String![]?);
+ method public java.util.Map<java.lang.String!,java.lang.Boolean!> parseResult(int, android.content.Intent?);
+ field public static final String ACTION_REQUEST_PERMISSIONS = "androidx.activity.result.contract.action.REQUEST_PERMISSIONS";
+ field public static final String EXTRA_PERMISSIONS = "androidx.activity.result.contract.extra.PERMISSIONS";
+ field public static final String EXTRA_PERMISSION_GRANT_RESULTS = "androidx.activity.result.contract.extra.PERMISSION_GRANT_RESULTS";
+ }
+
+ public static final class ActivityResultContracts.RequestPermission extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,java.lang.Boolean> {
+ ctor public ActivityResultContracts.RequestPermission();
+ method public android.content.Intent createIntent(android.content.Context, String);
+ method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.lang.Boolean!>? getSynchronousResult(android.content.Context, String?);
+ method public Boolean parseResult(int, android.content.Intent?);
+ }
+
+ public static final class ActivityResultContracts.StartActivityForResult extends androidx.activity.result.contract.ActivityResultContract<android.content.Intent,androidx.activity.result.ActivityResult> {
+ ctor public ActivityResultContracts.StartActivityForResult();
+ method public android.content.Intent createIntent(android.content.Context, android.content.Intent);
+ method public androidx.activity.result.ActivityResult parseResult(int, android.content.Intent?);
+ field public static final String EXTRA_ACTIVITY_OPTIONS_BUNDLE = "androidx.activity.result.contract.extra.ACTIVITY_OPTIONS_BUNDLE";
+ }
+
+ public static final class ActivityResultContracts.StartIntentSenderForResult extends androidx.activity.result.contract.ActivityResultContract<androidx.activity.result.IntentSenderRequest,androidx.activity.result.ActivityResult> {
+ ctor public ActivityResultContracts.StartIntentSenderForResult();
+ method public android.content.Intent createIntent(android.content.Context, androidx.activity.result.IntentSenderRequest);
+ method public androidx.activity.result.ActivityResult parseResult(int, android.content.Intent?);
+ field public static final String ACTION_INTENT_SENDER_REQUEST = "androidx.activity.result.contract.action.INTENT_SENDER_REQUEST";
+ field public static final String EXTRA_INTENT_SENDER_REQUEST = "androidx.activity.result.contract.extra.INTENT_SENDER_REQUEST";
+ field public static final String EXTRA_SEND_INTENT_EXCEPTION = "androidx.activity.result.contract.extra.SEND_INTENT_EXCEPTION";
+ }
+
+ public static class ActivityResultContracts.TakePicture extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,java.lang.Boolean> {
+ ctor public ActivityResultContracts.TakePicture();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.lang.Boolean!>? getSynchronousResult(android.content.Context, android.net.Uri);
+ method public final Boolean parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.TakePicturePreview extends androidx.activity.result.contract.ActivityResultContract<java.lang.Void,android.graphics.Bitmap> {
+ ctor public ActivityResultContracts.TakePicturePreview();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, Void?);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.graphics.Bitmap!>? getSynchronousResult(android.content.Context, Void?);
+ method public final android.graphics.Bitmap? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.TakeVideo extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,android.graphics.Bitmap> {
+ ctor public ActivityResultContracts.TakeVideo();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.graphics.Bitmap!>? getSynchronousResult(android.content.Context, android.net.Uri);
+ method public final android.graphics.Bitmap? parseResult(int, android.content.Intent?);
+ }
+
+}
+
diff --git a/activity/activity/api/res-1.2.0-beta01.txt b/activity/activity/api/res-1.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/activity/activity/api/res-1.2.0-beta01.txt
diff --git a/activity/activity/api/restricted_1.2.0-beta01.txt b/activity/activity/api/restricted_1.2.0-beta01.txt
new file mode 100644
index 0000000..823a4ed
--- /dev/null
+++ b/activity/activity/api/restricted_1.2.0-beta01.txt
@@ -0,0 +1,258 @@
+// Signature format: 3.0
+package androidx.activity {
+
+ public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.activity.contextaware.ContextAware androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+ ctor public ComponentActivity();
+ ctor @ContentView public ComponentActivity(@LayoutRes int);
+ method public final void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public final androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
+ method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+ method @Deprecated public Object? getLastCustomNonConfigurationInstance();
+ method public final androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+ method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+ method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ method @Deprecated @CallSuper protected void onActivityResult(int, int, android.content.Intent?);
+ method @Deprecated @CallSuper public void onRequestPermissionsResult(int, String![], int[]);
+ method @Deprecated public Object? onRetainCustomNonConfigurationInstance();
+ method public final Object? onRetainNonConfigurationInstance();
+ method public android.content.Context? peekAvailableContext();
+ method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method @Deprecated public void startActivityForResult(android.content.Intent!, int);
+ method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int) throws android.content.IntentSender.SendIntentException;
+ method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ }
+
+ public abstract class OnBackPressedCallback {
+ ctor public OnBackPressedCallback(boolean);
+ method @MainThread public abstract void handleOnBackPressed();
+ method @MainThread public final boolean isEnabled();
+ method @MainThread public final void remove();
+ method @MainThread public final void setEnabled(boolean);
+ }
+
+ public final class OnBackPressedDispatcher {
+ ctor public OnBackPressedDispatcher();
+ ctor public OnBackPressedDispatcher(Runnable?);
+ method @MainThread public void addCallback(androidx.activity.OnBackPressedCallback);
+ method @MainThread public void addCallback(androidx.lifecycle.LifecycleOwner, androidx.activity.OnBackPressedCallback);
+ method @MainThread public boolean hasEnabledCallbacks();
+ method @MainThread public void onBackPressed();
+ }
+
+ public interface OnBackPressedDispatcherOwner extends androidx.lifecycle.LifecycleOwner {
+ method public androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+ }
+
+}
+
+package androidx.activity.contextaware {
+
+ public interface ContextAware {
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public android.content.Context? peekAvailableContext();
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public final class ContextAwareHelper {
+ ctor public ContextAwareHelper();
+ method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ method public void clearAvailableContext();
+ method public void dispatchOnContextAvailable(android.content.Context);
+ method public android.content.Context? peekAvailableContext();
+ method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+ }
+
+ public interface OnContextAvailableListener {
+ method public void onContextAvailable(android.content.Context);
+ }
+
+}
+
+package androidx.activity.result {
+
+ public final class ActivityResult implements android.os.Parcelable {
+ ctor public ActivityResult(int, android.content.Intent?);
+ method public int describeContents();
+ method public android.content.Intent? getData();
+ method public int getResultCode();
+ method public static String resultCodeToString(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<androidx.activity.result.ActivityResult!> CREATOR;
+ }
+
+ public interface ActivityResultCallback<O> {
+ method public void onActivityResult(O!);
+ }
+
+ public interface ActivityResultCaller {
+ method public <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+ }
+
+ public abstract class ActivityResultLauncher<I> {
+ ctor public ActivityResultLauncher();
+ method public abstract androidx.activity.result.contract.ActivityResultContract<I!,?> getContract();
+ method public void launch(I!);
+ method public abstract void launch(I!, androidx.core.app.ActivityOptionsCompat?);
+ method @MainThread public abstract void unregister();
+ }
+
+ public abstract class ActivityResultRegistry {
+ ctor public ActivityResultRegistry();
+ method @MainThread public final boolean dispatchResult(int, int, android.content.Intent?);
+ method @MainThread public final <O> boolean dispatchResult(int, O!);
+ method @MainThread public abstract <I, O> void onLaunch(int, androidx.activity.result.contract.ActivityResultContract<I!,O!>, I!, androidx.core.app.ActivityOptionsCompat?);
+ method public final void onRestoreInstanceState(android.os.Bundle?);
+ method public final void onSaveInstanceState(android.os.Bundle);
+ method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> register(String, androidx.lifecycle.LifecycleOwner, androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> register(String, androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ }
+
+ public interface ActivityResultRegistryOwner {
+ method public androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
+ }
+
+ public final class IntentSenderRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.content.Intent? getFillInIntent();
+ method public int getFlagsMask();
+ method public int getFlagsValues();
+ method public android.content.IntentSender getIntentSender();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<androidx.activity.result.IntentSenderRequest!> CREATOR;
+ }
+
+ public static final class IntentSenderRequest.Builder {
+ ctor public IntentSenderRequest.Builder(android.content.IntentSender);
+ ctor public IntentSenderRequest.Builder(android.app.PendingIntent);
+ method public androidx.activity.result.IntentSenderRequest build();
+ method public androidx.activity.result.IntentSenderRequest.Builder setFillInIntent(android.content.Intent?);
+ method public androidx.activity.result.IntentSenderRequest.Builder setFlags(int, int);
+ }
+
+}
+
+package androidx.activity.result.contract {
+
+ public abstract class ActivityResultContract<I, O> {
+ ctor public ActivityResultContract();
+ method public abstract android.content.Intent createIntent(android.content.Context, I!);
+ method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<O!>? getSynchronousResult(android.content.Context, I!);
+ method public abstract O! parseResult(int, android.content.Intent?);
+ }
+
+ public static final class ActivityResultContract.SynchronousResult<T> {
+ ctor public ActivityResultContract.SynchronousResult(T!);
+ method public T! getValue();
+ }
+
+ public final class ActivityResultContracts {
+ }
+
+ public static class ActivityResultContracts.CreateDocument extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,android.net.Uri> {
+ ctor public ActivityResultContracts.CreateDocument();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String);
+ method public final android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.GetContent extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,android.net.Uri> {
+ ctor public ActivityResultContracts.GetContent();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String);
+ method public final android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.GetMultipleContents extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,java.util.List<android.net.Uri>> {
+ ctor public ActivityResultContracts.GetMultipleContents();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.List<android.net.Uri!>!>? getSynchronousResult(android.content.Context, String);
+ method public final java.util.List<android.net.Uri!> parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.OpenDocument extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],android.net.Uri> {
+ ctor public ActivityResultContracts.OpenDocument();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String![]);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String![]);
+ method public final android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.OpenDocumentTree extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,android.net.Uri> {
+ ctor public ActivityResultContracts.OpenDocumentTree();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri?);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, android.net.Uri?);
+ method public final android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.OpenMultipleDocuments extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],java.util.List<android.net.Uri>> {
+ ctor public ActivityResultContracts.OpenMultipleDocuments();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, String![]);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.List<android.net.Uri!>!>? getSynchronousResult(android.content.Context, String![]);
+ method public final java.util.List<android.net.Uri!> parseResult(int, android.content.Intent?);
+ }
+
+ public static final class ActivityResultContracts.PickContact extends androidx.activity.result.contract.ActivityResultContract<java.lang.Void,android.net.Uri> {
+ ctor public ActivityResultContracts.PickContact();
+ method public android.content.Intent createIntent(android.content.Context, Void?);
+ method public android.net.Uri? parseResult(int, android.content.Intent?);
+ }
+
+ public static final class ActivityResultContracts.RequestMultiplePermissions extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],java.util.Map<java.lang.String,java.lang.Boolean>> {
+ ctor public ActivityResultContracts.RequestMultiplePermissions();
+ method public android.content.Intent createIntent(android.content.Context, String![]);
+ method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.Map<java.lang.String!,java.lang.Boolean!>!>? getSynchronousResult(android.content.Context, String![]?);
+ method public java.util.Map<java.lang.String!,java.lang.Boolean!> parseResult(int, android.content.Intent?);
+ field public static final String ACTION_REQUEST_PERMISSIONS = "androidx.activity.result.contract.action.REQUEST_PERMISSIONS";
+ field public static final String EXTRA_PERMISSIONS = "androidx.activity.result.contract.extra.PERMISSIONS";
+ field public static final String EXTRA_PERMISSION_GRANT_RESULTS = "androidx.activity.result.contract.extra.PERMISSION_GRANT_RESULTS";
+ }
+
+ public static final class ActivityResultContracts.RequestPermission extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,java.lang.Boolean> {
+ ctor public ActivityResultContracts.RequestPermission();
+ method public android.content.Intent createIntent(android.content.Context, String);
+ method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.lang.Boolean!>? getSynchronousResult(android.content.Context, String?);
+ method public Boolean parseResult(int, android.content.Intent?);
+ }
+
+ public static final class ActivityResultContracts.StartActivityForResult extends androidx.activity.result.contract.ActivityResultContract<android.content.Intent,androidx.activity.result.ActivityResult> {
+ ctor public ActivityResultContracts.StartActivityForResult();
+ method public android.content.Intent createIntent(android.content.Context, android.content.Intent);
+ method public androidx.activity.result.ActivityResult parseResult(int, android.content.Intent?);
+ field public static final String EXTRA_ACTIVITY_OPTIONS_BUNDLE = "androidx.activity.result.contract.extra.ACTIVITY_OPTIONS_BUNDLE";
+ }
+
+ public static final class ActivityResultContracts.StartIntentSenderForResult extends androidx.activity.result.contract.ActivityResultContract<androidx.activity.result.IntentSenderRequest,androidx.activity.result.ActivityResult> {
+ ctor public ActivityResultContracts.StartIntentSenderForResult();
+ method public android.content.Intent createIntent(android.content.Context, androidx.activity.result.IntentSenderRequest);
+ method public androidx.activity.result.ActivityResult parseResult(int, android.content.Intent?);
+ field public static final String ACTION_INTENT_SENDER_REQUEST = "androidx.activity.result.contract.action.INTENT_SENDER_REQUEST";
+ field public static final String EXTRA_INTENT_SENDER_REQUEST = "androidx.activity.result.contract.extra.INTENT_SENDER_REQUEST";
+ field public static final String EXTRA_SEND_INTENT_EXCEPTION = "androidx.activity.result.contract.extra.SEND_INTENT_EXCEPTION";
+ }
+
+ public static class ActivityResultContracts.TakePicture extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,java.lang.Boolean> {
+ ctor public ActivityResultContracts.TakePicture();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.lang.Boolean!>? getSynchronousResult(android.content.Context, android.net.Uri);
+ method public final Boolean parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.TakePicturePreview extends androidx.activity.result.contract.ActivityResultContract<java.lang.Void,android.graphics.Bitmap> {
+ ctor public ActivityResultContracts.TakePicturePreview();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, Void?);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.graphics.Bitmap!>? getSynchronousResult(android.content.Context, Void?);
+ method public final android.graphics.Bitmap? parseResult(int, android.content.Intent?);
+ }
+
+ public static class ActivityResultContracts.TakeVideo extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,android.graphics.Bitmap> {
+ ctor public ActivityResultContracts.TakeVideo();
+ method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri);
+ method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.graphics.Bitmap!>? getSynchronousResult(android.content.Context, android.net.Uri);
+ method public final android.graphics.Bitmap? parseResult(int, android.content.Intent?);
+ }
+
+}
+
diff --git a/activity/activity/src/main/java/androidx/activity/result/ActivityResultRegistry.java b/activity/activity/src/main/java/androidx/activity/result/ActivityResultRegistry.java
index 1b08ee8..99193f8 100644
--- a/activity/activity/src/main/java/androidx/activity/result/ActivityResultRegistry.java
+++ b/activity/activity/src/main/java/androidx/activity/result/ActivityResultRegistry.java
@@ -58,8 +58,10 @@
private static final String LOG_TAG = "ActivityResultRegistry";
+ private static final int INITIAL_REQUEST_CODE_VALUE = 0x00010000;
+
// Use upper 16 bits for request codes
- private final AtomicInteger mNextRc = new AtomicInteger(0x00010000);
+ private final AtomicInteger mNextRc = new AtomicInteger(INITIAL_REQUEST_CODE_VALUE);
private final Map<Integer, String> mRcToKey = new HashMap<>();
private final Map<String, Integer> mKeyToRc = new HashMap<>();
private final Map<String, LifecycleContainer> mKeyToLifecycleContainers = new HashMap<>();
@@ -278,7 +280,7 @@
for (int i = 0; i < numKeys; i++) {
bindRcKey(rcs.get(i), keys.get(i));
}
- mNextRc.set(numKeys);
+ mNextRc.set(INITIAL_REQUEST_CODE_VALUE + numKeys);
mPendingResults.putAll(
savedInstanceState.getBundle(KEY_COMPONENT_ACTIVITY_PENDING_RESULTS));
}
diff --git a/appcompat/appcompat-lint/build.gradle b/appcompat/appcompat-lint/build.gradle
index da60f47..51a3871 100644
--- a/appcompat/appcompat-lint/build.gradle
+++ b/appcompat/appcompat-lint/build.gradle
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+
+import androidx.build.CompilationTarget
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
import androidx.build.Publish
@@ -38,6 +40,7 @@
name = "AppCompat Lint Checks"
toolingProject = true
publish = Publish.NONE
+ compilationTarget = CompilationTarget.HOST
mavenVersion = LibraryVersions.APPCOMPAT
mavenGroup = LibraryGroups.APPCOMPAT
inceptionYear = "2019"
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-hdpi/abc_ic_menu_copy_mtrl_am_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-hdpi/abc_ic_menu_copy_mtrl_am_alpha.png
deleted file mode 100644
index a262b0c..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-hdpi/abc_ic_menu_copy_mtrl_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-hdpi/abc_ic_menu_cut_mtrl_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-hdpi/abc_ic_menu_cut_mtrl_alpha.png
deleted file mode 100644
index d8eaf07..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-hdpi/abc_ic_menu_cut_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-mdpi/abc_ic_menu_copy_mtrl_am_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-mdpi/abc_ic_menu_copy_mtrl_am_alpha.png
deleted file mode 100644
index 254f806..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-mdpi/abc_ic_menu_copy_mtrl_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-mdpi/abc_ic_menu_cut_mtrl_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-mdpi/abc_ic_menu_cut_mtrl_alpha.png
deleted file mode 100644
index f9cba8f..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-mdpi/abc_ic_menu_cut_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-xhdpi/abc_ic_menu_copy_mtrl_am_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-xhdpi/abc_ic_menu_copy_mtrl_am_alpha.png
deleted file mode 100644
index 198a842..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-xhdpi/abc_ic_menu_copy_mtrl_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-xhdpi/abc_ic_menu_cut_mtrl_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-xhdpi/abc_ic_menu_cut_mtrl_alpha.png
deleted file mode 100644
index 87bf8d3..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-xhdpi/abc_ic_menu_cut_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxhdpi/abc_ic_menu_copy_mtrl_am_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-xxhdpi/abc_ic_menu_copy_mtrl_am_alpha.png
deleted file mode 100644
index 284c3c2..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxhdpi/abc_ic_menu_copy_mtrl_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxhdpi/abc_ic_menu_cut_mtrl_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-xxhdpi/abc_ic_menu_cut_mtrl_alpha.png
deleted file mode 100644
index 3cdb6cf..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxhdpi/abc_ic_menu_cut_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxxhdpi/abc_ic_menu_copy_mtrl_am_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-xxxhdpi/abc_ic_menu_copy_mtrl_am_alpha.png
deleted file mode 100644
index 7d4c690..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxxhdpi/abc_ic_menu_copy_mtrl_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxxhdpi/abc_ic_menu_cut_mtrl_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-xxxhdpi/abc_ic_menu_cut_mtrl_alpha.png
deleted file mode 100644
index 90fe333..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxxhdpi/abc_ic_menu_cut_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/values-as/strings.xml b/appcompat/appcompat/src/main/res/values-as/strings.xml
index 1a3b4a1..4314fe9 100644
--- a/appcompat/appcompat/src/main/res/values-as/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-as/strings.xml
@@ -21,7 +21,7 @@
<string name="abc_action_bar_up_description" msgid="8388173803310557296">"ওপৰলৈ যাওক"</string>
<string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"অধিক বিকল্প"</string>
<string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"সংকোচন কৰক"</string>
- <string name="abc_searchview_description_search" msgid="3417662926640357176">"সন্ধান"</string>
+ <string name="abc_searchview_description_search" msgid="3417662926640357176">"Search"</string>
<string name="abc_search_hint" msgid="7208076849092622260">"সন্ধান কৰক…"</string>
<string name="abc_searchview_description_query" msgid="693312494995508443">"সন্ধান কৰা প্ৰশ্ন"</string>
<string name="abc_searchview_description_clear" msgid="3741173234950517107">"সন্ধান কৰা প্ৰশ্ন মচক"</string>
@@ -33,7 +33,7 @@
<string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"ইয়াৰ জৰিয়তে শ্বেয়াৰ কৰক"</string>
<string name="abc_capital_on" msgid="884982626291842264">"অন"</string>
<string name="abc_capital_off" msgid="4215997306490295099">"অফ"</string>
- <string name="search_menu_title" msgid="6264217191555673260">"সন্ধান"</string>
+ <string name="search_menu_title" msgid="6264217191555673260">"Search"</string>
<string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"Menu+"</string>
<string name="abc_menu_meta_shortcut_label" msgid="4192209724446364286">"Meta+"</string>
<string name="abc_menu_ctrl_shortcut_label" msgid="2223301931652355242">"Ctrl+"</string>
diff --git a/appcompat/appcompat/src/main/res/values-cs/strings.xml b/appcompat/appcompat/src/main/res/values-cs/strings.xml
index d38f873..907c0fe 100644
--- a/appcompat/appcompat/src/main/res/values-cs/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-cs/strings.xml
@@ -19,7 +19,7 @@
<string name="abc_action_mode_done" msgid="4692188335987374352">"Hotovo"</string>
<string name="abc_action_bar_home_description" msgid="5976598919945601918">"Přejít na plochu"</string>
<string name="abc_action_bar_up_description" msgid="8388173803310557296">"Přejít nahoru"</string>
- <string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"Více možností"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"Další možnosti"</string>
<string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"Sbalit"</string>
<string name="abc_searchview_description_search" msgid="3417662926640357176">"Hledat"</string>
<string name="abc_search_hint" msgid="7208076849092622260">"Vyhledat…"</string>
diff --git a/appcompat/appcompat/src/main/res/values-kn/strings.xml b/appcompat/appcompat/src/main/res/values-kn/strings.xml
index 40454c7..9a11465 100644
--- a/appcompat/appcompat/src/main/res/values-kn/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-kn/strings.xml
@@ -21,7 +21,7 @@
<string name="abc_action_bar_up_description" msgid="8388173803310557296">"ಮೇಲಕ್ಕೆ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಿ"</string>
<string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"ಇನ್ನಷ್ಟು ಆಯ್ಕೆಗಳು"</string>
<string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"ಕುಗ್ಗಿಸಿ"</string>
- <string name="abc_searchview_description_search" msgid="3417662926640357176">"ಹುಡುಕಿ"</string>
+ <string name="abc_searchview_description_search" msgid="3417662926640357176">"Search"</string>
<string name="abc_search_hint" msgid="7208076849092622260">"ಹುಡುಕಿ…"</string>
<string name="abc_searchview_description_query" msgid="693312494995508443">"ಪ್ರಶ್ನೆಯನ್ನು ಹುಡುಕಿ"</string>
<string name="abc_searchview_description_clear" msgid="3741173234950517107">"ಪ್ರಶ್ನೆಯನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
@@ -33,7 +33,7 @@
<string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"ಇವರೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="abc_capital_on" msgid="884982626291842264">"ಆನ್"</string>
<string name="abc_capital_off" msgid="4215997306490295099">"ಆಫ್"</string>
- <string name="search_menu_title" msgid="6264217191555673260">"ಹುಡುಕಿ"</string>
+ <string name="search_menu_title" msgid="6264217191555673260">"Search"</string>
<string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"Menu+"</string>
<string name="abc_menu_meta_shortcut_label" msgid="4192209724446364286">"Meta+"</string>
<string name="abc_menu_ctrl_shortcut_label" msgid="2223301931652355242">"Ctrl+"</string>
diff --git a/appcompat/appcompat/src/main/res/values-ml/strings.xml b/appcompat/appcompat/src/main/res/values-ml/strings.xml
index 2acae41..242ec2c 100644
--- a/appcompat/appcompat/src/main/res/values-ml/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-ml/strings.xml
@@ -21,7 +21,7 @@
<string name="abc_action_bar_up_description" msgid="8388173803310557296">"മുകളിലേക്ക് പോവുക"</string>
<string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"കൂടുതൽ ഓപ്ഷനുകൾ"</string>
<string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"ചുരുക്കുക"</string>
- <string name="abc_searchview_description_search" msgid="3417662926640357176">"തിരയുക"</string>
+ <string name="abc_searchview_description_search" msgid="3417662926640357176">"Search"</string>
<string name="abc_search_hint" msgid="7208076849092622260">"തിരയുക…"</string>
<string name="abc_searchview_description_query" msgid="693312494995508443">"ചോദ്യം തിരയുക"</string>
<string name="abc_searchview_description_clear" msgid="3741173234950517107">"ചോദ്യം മായ്ക്കുക"</string>
@@ -33,7 +33,7 @@
<string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"ഇനിപ്പറയുന്നതുമായി പങ്കിടുക"</string>
<string name="abc_capital_on" msgid="884982626291842264">"ഓൺ"</string>
<string name="abc_capital_off" msgid="4215997306490295099">"ഓഫ്"</string>
- <string name="search_menu_title" msgid="6264217191555673260">"തിരയുക"</string>
+ <string name="search_menu_title" msgid="6264217191555673260">"Search"</string>
<string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"മെനു+"</string>
<string name="abc_menu_meta_shortcut_label" msgid="4192209724446364286">"മെറ്റ+"</string>
<string name="abc_menu_ctrl_shortcut_label" msgid="2223301931652355242">"Ctrl+"</string>
diff --git a/appcompat/appcompat/src/main/res/values-mr/strings.xml b/appcompat/appcompat/src/main/res/values-mr/strings.xml
index 4bc6cb1..f4adb38 100644
--- a/appcompat/appcompat/src/main/res/values-mr/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-mr/strings.xml
@@ -21,7 +21,7 @@
<string name="abc_action_bar_up_description" msgid="8388173803310557296">"वर नेव्हिगेट करा"</string>
<string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"आणखी पर्याय"</string>
<string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"कोलॅप्स करा"</string>
- <string name="abc_searchview_description_search" msgid="3417662926640357176">"शोध"</string>
+ <string name="abc_searchview_description_search" msgid="3417662926640357176">"Search"</string>
<string name="abc_search_hint" msgid="7208076849092622260">"शोधा…"</string>
<string name="abc_searchview_description_query" msgid="693312494995508443">"शोध क्वेरी"</string>
<string name="abc_searchview_description_clear" msgid="3741173234950517107">"क्वेरी साफ करा"</string>
@@ -33,7 +33,7 @@
<string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"यांच्यासोबत शेअर करा"</string>
<string name="abc_capital_on" msgid="884982626291842264">"सुरू"</string>
<string name="abc_capital_off" msgid="4215997306490295099">"बंद"</string>
- <string name="search_menu_title" msgid="6264217191555673260">"शोध"</string>
+ <string name="search_menu_title" msgid="6264217191555673260">"Search"</string>
<string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"मेनू+"</string>
<string name="abc_menu_meta_shortcut_label" msgid="4192209724446364286">"Meta+"</string>
<string name="abc_menu_ctrl_shortcut_label" msgid="2223301931652355242">"Ctrl+"</string>
diff --git a/appcompat/appcompat/src/main/res/values-nl/strings.xml b/appcompat/appcompat/src/main/res/values-nl/strings.xml
index 0e0db0a..2a6959d 100644
--- a/appcompat/appcompat/src/main/res/values-nl/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-nl/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="abc_action_mode_done" msgid="4692188335987374352">"Gereed"</string>
+ <string name="abc_action_mode_done" msgid="4692188335987374352">"Klaar"</string>
<string name="abc_action_bar_home_description" msgid="5976598919945601918">"Navigeren naar startpositie"</string>
<string name="abc_action_bar_up_description" msgid="8388173803310557296">"Omhoog navigeren"</string>
<string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"Meer opties"</string>
diff --git a/appcompat/appcompat/src/main/res/values-or/strings.xml b/appcompat/appcompat/src/main/res/values-or/strings.xml
index c1af6db..6f29662 100644
--- a/appcompat/appcompat/src/main/res/values-or/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-or/strings.xml
@@ -21,7 +21,7 @@
<string name="abc_action_bar_up_description" msgid="8388173803310557296">"ଉପରକୁ ନେଭିଗେଟ୍ କରନ୍ତୁ"</string>
<string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"ଅଧିକ ବିକଳ୍ପ"</string>
<string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"ସଂକୁଚିତ କରନ୍ତୁ"</string>
- <string name="abc_searchview_description_search" msgid="3417662926640357176">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+ <string name="abc_searchview_description_search" msgid="3417662926640357176">"Search"</string>
<string name="abc_search_hint" msgid="7208076849092622260">"ସର୍ଚ୍ଚ କରନ୍ତୁ…"</string>
<string name="abc_searchview_description_query" msgid="693312494995508443">"ସର୍ଚ୍ଚ କ୍ୱେରୀ"</string>
<string name="abc_searchview_description_clear" msgid="3741173234950517107">"କ୍ୱେରୀ ଖାଲି କରନ୍ତୁ"</string>
@@ -33,7 +33,7 @@
<string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"ଏହାଙ୍କ ସହ ସେୟାର୍ କରନ୍ତୁ"</string>
<string name="abc_capital_on" msgid="884982626291842264">"ଅନ୍"</string>
<string name="abc_capital_off" msgid="4215997306490295099">"ବନ୍ଦ"</string>
- <string name="search_menu_title" msgid="6264217191555673260">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+ <string name="search_menu_title" msgid="6264217191555673260">"Search"</string>
<string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"ମେନୁ"</string>
<string name="abc_menu_meta_shortcut_label" msgid="4192209724446364286">"Meta+"</string>
<string name="abc_menu_ctrl_shortcut_label" msgid="2223301931652355242">"Ctrl+"</string>
diff --git a/appcompat/appcompat/src/main/res/values-te/strings.xml b/appcompat/appcompat/src/main/res/values-te/strings.xml
index 80f7d0d..9a284b7 100644
--- a/appcompat/appcompat/src/main/res/values-te/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-te/strings.xml
@@ -21,7 +21,7 @@
<string name="abc_action_bar_up_description" msgid="8388173803310557296">"పైకి నావిగేట్ చేస్తుంది"</string>
<string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"మరిన్ని ఎంపికలు"</string>
<string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"కుదిస్తుంది"</string>
- <string name="abc_searchview_description_search" msgid="3417662926640357176">"శోధన"</string>
+ <string name="abc_searchview_description_search" msgid="3417662926640357176">"సెర్చ్"</string>
<string name="abc_search_hint" msgid="7208076849092622260">"వెతకండి…"</string>
<string name="abc_searchview_description_query" msgid="693312494995508443">"శోధన ప్రశ్న"</string>
<string name="abc_searchview_description_clear" msgid="3741173234950517107">"ప్రశ్నను తీసివేస్తుంది"</string>
@@ -33,7 +33,7 @@
<string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"వీరితో షేర్ చేస్తుంది"</string>
<string name="abc_capital_on" msgid="884982626291842264">"ఆన్"</string>
<string name="abc_capital_off" msgid="4215997306490295099">"ఆఫ్"</string>
- <string name="search_menu_title" msgid="6264217191555673260">"శోధన"</string>
+ <string name="search_menu_title" msgid="6264217191555673260">"సెర్చ్"</string>
<string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"Menu+"</string>
<string name="abc_menu_meta_shortcut_label" msgid="4192209724446364286">"Meta+"</string>
<string name="abc_menu_ctrl_shortcut_label" msgid="2223301931652355242">"Ctrl+"</string>
diff --git a/appsearch/appsearch/api/current.txt b/appsearch/appsearch/api/current.txt
index 1c5f6a9..a663d92 100644
--- a/appsearch/appsearch/api/current.txt
+++ b/appsearch/appsearch/api/current.txt
@@ -177,6 +177,54 @@
method public BuilderType setTtlMillis(long);
}
+ public final class MatchInfo {
+ method public CharSequence getExactMatch();
+ method public androidx.appsearch.app.MatchInfo.MatchRange getExactMatchPosition();
+ method public String getFullText();
+ method public String getPropertyPath();
+ method public CharSequence getSnippet();
+ method public androidx.appsearch.app.MatchInfo.MatchRange getSnippetPosition();
+ }
+
+ public static class MatchInfo.MatchRange {
+ method public int getEnd();
+ method public int getStart();
+ }
+
+ public final class SearchResults implements java.io.Closeable {
+ method public void close();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchResult<java.util.List<androidx.appsearch.app.SearchResults.Result!>!>!> getNextPage();
+ }
+
+ public static final class SearchResults.Result {
+ method public androidx.appsearch.app.GenericDocument getDocument();
+ method public java.util.List<androidx.appsearch.app.MatchInfo!>? getMatches();
+ }
+
+ public final class SearchSpec {
+ field public static final int ORDER_ASCENDING = 1; // 0x1
+ field public static final int ORDER_DESCENDING = 0; // 0x0
+ field public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2; // 0x2
+ field public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1; // 0x1
+ field public static final int RANKING_STRATEGY_NONE = 0; // 0x0
+ field public static final int TERM_MATCH_EXACT_ONLY = 1; // 0x1
+ field public static final int TERM_MATCH_PREFIX = 2; // 0x2
+ }
+
+ public static final class SearchSpec.Builder {
+ ctor public SearchSpec.Builder();
+ method public androidx.appsearch.app.SearchSpec build();
+ method public androidx.appsearch.app.SearchSpec.Builder setMaxSnippetSize(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setNamespaces(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder setNumPerPage(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setOrder(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setRankingStrategy(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setSchemaTypes(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder setSnippetCount(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setSnippetCountPerProperty(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setTermMatch(int);
+ }
+
}
package androidx.appsearch.exceptions {
diff --git a/appsearch/appsearch/api/public_plus_experimental_current.txt b/appsearch/appsearch/api/public_plus_experimental_current.txt
index 1c5f6a9..a663d92 100644
--- a/appsearch/appsearch/api/public_plus_experimental_current.txt
+++ b/appsearch/appsearch/api/public_plus_experimental_current.txt
@@ -177,6 +177,54 @@
method public BuilderType setTtlMillis(long);
}
+ public final class MatchInfo {
+ method public CharSequence getExactMatch();
+ method public androidx.appsearch.app.MatchInfo.MatchRange getExactMatchPosition();
+ method public String getFullText();
+ method public String getPropertyPath();
+ method public CharSequence getSnippet();
+ method public androidx.appsearch.app.MatchInfo.MatchRange getSnippetPosition();
+ }
+
+ public static class MatchInfo.MatchRange {
+ method public int getEnd();
+ method public int getStart();
+ }
+
+ public final class SearchResults implements java.io.Closeable {
+ method public void close();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchResult<java.util.List<androidx.appsearch.app.SearchResults.Result!>!>!> getNextPage();
+ }
+
+ public static final class SearchResults.Result {
+ method public androidx.appsearch.app.GenericDocument getDocument();
+ method public java.util.List<androidx.appsearch.app.MatchInfo!>? getMatches();
+ }
+
+ public final class SearchSpec {
+ field public static final int ORDER_ASCENDING = 1; // 0x1
+ field public static final int ORDER_DESCENDING = 0; // 0x0
+ field public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2; // 0x2
+ field public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1; // 0x1
+ field public static final int RANKING_STRATEGY_NONE = 0; // 0x0
+ field public static final int TERM_MATCH_EXACT_ONLY = 1; // 0x1
+ field public static final int TERM_MATCH_PREFIX = 2; // 0x2
+ }
+
+ public static final class SearchSpec.Builder {
+ ctor public SearchSpec.Builder();
+ method public androidx.appsearch.app.SearchSpec build();
+ method public androidx.appsearch.app.SearchSpec.Builder setMaxSnippetSize(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setNamespaces(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder setNumPerPage(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setOrder(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setRankingStrategy(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setSchemaTypes(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder setSnippetCount(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setSnippetCountPerProperty(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setTermMatch(int);
+ }
+
}
package androidx.appsearch.exceptions {
diff --git a/appsearch/appsearch/api/restricted_current.txt b/appsearch/appsearch/api/restricted_current.txt
index 1c5f6a9..a663d92 100644
--- a/appsearch/appsearch/api/restricted_current.txt
+++ b/appsearch/appsearch/api/restricted_current.txt
@@ -177,6 +177,54 @@
method public BuilderType setTtlMillis(long);
}
+ public final class MatchInfo {
+ method public CharSequence getExactMatch();
+ method public androidx.appsearch.app.MatchInfo.MatchRange getExactMatchPosition();
+ method public String getFullText();
+ method public String getPropertyPath();
+ method public CharSequence getSnippet();
+ method public androidx.appsearch.app.MatchInfo.MatchRange getSnippetPosition();
+ }
+
+ public static class MatchInfo.MatchRange {
+ method public int getEnd();
+ method public int getStart();
+ }
+
+ public final class SearchResults implements java.io.Closeable {
+ method public void close();
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchResult<java.util.List<androidx.appsearch.app.SearchResults.Result!>!>!> getNextPage();
+ }
+
+ public static final class SearchResults.Result {
+ method public androidx.appsearch.app.GenericDocument getDocument();
+ method public java.util.List<androidx.appsearch.app.MatchInfo!>? getMatches();
+ }
+
+ public final class SearchSpec {
+ field public static final int ORDER_ASCENDING = 1; // 0x1
+ field public static final int ORDER_DESCENDING = 0; // 0x0
+ field public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2; // 0x2
+ field public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1; // 0x1
+ field public static final int RANKING_STRATEGY_NONE = 0; // 0x0
+ field public static final int TERM_MATCH_EXACT_ONLY = 1; // 0x1
+ field public static final int TERM_MATCH_PREFIX = 2; // 0x2
+ }
+
+ public static final class SearchSpec.Builder {
+ ctor public SearchSpec.Builder();
+ method public androidx.appsearch.app.SearchSpec build();
+ method public androidx.appsearch.app.SearchSpec.Builder setMaxSnippetSize(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setNamespaces(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder setNumPerPage(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setOrder(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setRankingStrategy(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setSchemaTypes(java.lang.String!...);
+ method public androidx.appsearch.app.SearchSpec.Builder setSnippetCount(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setSnippetCountPerProperty(int);
+ method public androidx.appsearch.app.SearchSpec.Builder setTermMatch(int);
+ }
+
}
package androidx.appsearch.exceptions {
diff --git a/appsearch/appsearch/build.gradle b/appsearch/appsearch/build.gradle
index db965f0..2e4e0c8 100644
--- a/appsearch/appsearch/build.gradle
+++ b/appsearch/appsearch/build.gradle
@@ -32,21 +32,6 @@
}
}
-// Add :icing as jarjar dependency
-// TODO(b/163453135): this code should be ported to use bundles instead of protos, and this
-// dependency removed. It should exist ONLY inside appsearch:local-backend.
-android.libraryVariants.all { variant ->
- def variantName = variant.name
- def suffix = variantName.capitalize()
- def jarjarConfigName = "jarjar${suffix}"
- def jarjarConf = configurations.register(jarjarConfigName)
- // Treat icing-java as a local jar and package it inside the aar.
- dependencies.add(jarjarConfigName, project.dependencies.project(
- path: ":icing",
- configuration: jarjarConfigName))
- dependencies.add("${variantName}Implementation", files(jarjarConf))
-}
-
dependencies {
api('androidx.annotation:annotation:1.1.0')
@@ -63,7 +48,6 @@
// This dependency is unused by the test implementation, but it's here to validate that
// icing's jarjar'ing of the Protobuf_lite doesn't conflict with external dependencies.
androidTestImplementation(PROTOBUF_LITE)
-
}
// Create a jar for use by appsearch-compiler:test
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTest.java
new file mode 100644
index 0000000..6b41cb9
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTest.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2020 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 androidx.appsearch.app;
+
+import static androidx.appsearch.app.AppSearchTestUtils.checkIsBatchResultSuccess;
+import static androidx.appsearch.app.AppSearchTestUtils.checkIsResultSuccess;
+import static androidx.appsearch.app.AppSearchTestUtils.doQuery;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.appsearch.annotation.AppSearchDocument;
+import androidx.appsearch.localbackend.LocalBackend;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+public class AnnotationProcessorTest {
+ private AppSearchManager mAppSearchManager;
+
+ @Before
+ public void setUp() throws Exception {
+ Context context = ApplicationProvider.getApplicationContext();
+ LocalBackend backend = LocalBackend.getInstance(context).getResultValue();
+ mAppSearchManager = checkIsResultSuccess(new AppSearchManager.Builder()
+ .setDatabaseName("testDb").setBackend(backend).build());
+
+ // Remove all documents from any instances that may have been created in the tests.
+ backend.resetAllDatabases().getResultValue();
+ }
+
+ @AppSearchDocument
+ static class Gift {
+ @AppSearchDocument.Uri String mUri;
+
+ // Collections
+ @AppSearchDocument.Property Collection<Long> mLongCollection; // 1a
+// @AppSearchDocument.Property Collection<Integer> mCollectInteger; // 1a
+ @AppSearchDocument.Property Collection<Double> mCollectDouble; // 1a
+// @AppSearchDocument.Property Collection<Float> mCollectFloat; // 1a
+ @AppSearchDocument.Property Collection<Boolean> mCollectBoolean; // 1a
+ @AppSearchDocument.Property Collection<byte[]> mCollectByteArr; // 1a
+ @AppSearchDocument.Property Collection<String> mCollectString; // 1b
+ @AppSearchDocument.Property Collection<Gift> mCollectGift; // 1c
+
+ // Arrays
+ @AppSearchDocument.Property Long[] mArrBoxLong; // 2a
+ @AppSearchDocument.Property long[] mArrUnboxLong; // 2b
+// @AppSearchDocument.Property Integer[] mArrBoxInteger; // 2a
+// @AppSearchDocument.Property int[] mArrUnboxInt; // 2a
+ @AppSearchDocument.Property Double[] mArrBoxDouble; // 2a
+ @AppSearchDocument.Property double[] mArrUnboxDouble; // 2b
+// @AppSearchDocument.Property Float[] mArrBoxFloat; // 2a
+// @AppSearchDocument.Property float[] mArrUnboxFloat; // 2a
+ @AppSearchDocument.Property Boolean[] mArrBoxBoolean; // 2a
+ @AppSearchDocument.Property boolean[] mArrUnboxBoolean; // 2b
+ @AppSearchDocument.Property byte[][] mArrUnboxByteArr; // 2b
+ @AppSearchDocument.Property Byte[] mBoxByteArr; // 2a
+ @AppSearchDocument.Property String[] mArrString; // 2b
+// @AppSearchDocument.Property Gift[] mArrGift; // 2c
+
+ // Single values
+ @AppSearchDocument.Property String mString; // 3a
+ @AppSearchDocument.Property Long mBoxLong; // 3a
+ @AppSearchDocument.Property long mUnboxLong; // 3b
+// @AppSearchDocument.Property Integer mBoxInteger; // 3a
+// @AppSearchDocument.Property int mUnboxInt; // 3b
+ @AppSearchDocument.Property Double mBoxDouble; // 3a
+ @AppSearchDocument.Property double mUnboxDouble; // 3b
+// @AppSearchDocument.Property Float mBoxFloat; // 3a
+// @AppSearchDocument.Property float mUnboxFloat; // 3b
+ @AppSearchDocument.Property Boolean mBoxBoolean; // 3a
+ @AppSearchDocument.Property boolean mUnboxBoolean; // 3b
+ @AppSearchDocument.Property byte[] mUnboxByteArr; // 3a
+// @AppSearchDocument.Property Gift mGift; // 3c
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof Gift)) {
+ return false;
+ }
+ Gift otherGift = (Gift) other;
+ assertThat(otherGift.mUri).isEqualTo(this.mUri);
+ assertThat(otherGift.mArrBoxBoolean).isEqualTo(this.mArrBoxBoolean);
+ assertThat(otherGift.mArrBoxDouble).isEqualTo(this.mArrBoxDouble);
+ assertThat(otherGift.mArrBoxLong).isEqualTo(this.mArrBoxLong);
+ assertThat(otherGift.mArrString).isEqualTo(this.mArrString);
+ assertThat(otherGift.mBoxByteArr).isEqualTo(this.mBoxByteArr);
+ assertThat(otherGift.mArrUnboxBoolean).isEqualTo(this.mArrUnboxBoolean);
+ assertThat(otherGift.mArrUnboxByteArr).isEqualTo(this.mArrUnboxByteArr);
+ assertThat(otherGift.mArrUnboxDouble).isEqualTo(this.mArrUnboxDouble);
+ assertThat(otherGift.mArrUnboxLong).isEqualTo(this.mArrUnboxLong);
+
+ assertThat(otherGift.mLongCollection).isEqualTo(this.mLongCollection);
+ assertThat(otherGift.mCollectBoolean).isEqualTo(this.mCollectBoolean);
+ assertThat(otherGift.mCollectString).isEqualTo(this.mCollectString);
+ assertThat(otherGift.mCollectDouble).isEqualTo(this.mCollectDouble);
+ assertThat(otherGift.mCollectGift).isEqualTo(this.mCollectGift);
+ checkCollectByteArr(otherGift.mCollectByteArr, this.mCollectByteArr);
+
+ assertThat(otherGift.mString).isEqualTo(this.mString);
+ assertThat(otherGift.mBoxLong).isEqualTo(this.mBoxLong);
+ assertThat(otherGift.mUnboxLong).isEqualTo(this.mUnboxLong);
+ assertThat(otherGift.mBoxDouble).isEqualTo(this.mBoxDouble);
+ assertThat(otherGift.mUnboxDouble).isEqualTo(this.mUnboxDouble);
+ assertThat(otherGift.mBoxBoolean).isEqualTo(this.mBoxBoolean);
+ assertThat(otherGift.mUnboxBoolean).isEqualTo(this.mUnboxBoolean);
+ assertThat(otherGift.mUnboxByteArr).isEqualTo(this.mUnboxByteArr);
+ return true;
+ }
+
+ void checkCollectByteArr(Collection<byte[]> first, Collection<byte[]> second) {
+ if (first == null && second == null) {
+ return;
+ }
+ assertThat(first).isNotNull();
+ assertThat(second).isNotNull();
+ assertThat(first.toArray()).isEqualTo(second.toArray());
+ }
+ }
+
+ @Test
+ public void testAnnotationProcessor() throws Exception {
+ //TODO(b/156296904) add test for int, float, GenericDocument, and class with
+ // @AppSearchDocument annotation
+ checkIsResultSuccess(mAppSearchManager.setSchema(
+ new AppSearchManager.SetSchemaRequest.Builder()
+ .addDataClass(Gift.class)
+ .build()));
+
+ // Create a Gift object and assign values.
+ Gift inputDataClass = new Gift();
+ inputDataClass.mUri = "gift.uri";
+
+ inputDataClass.mArrBoxBoolean = new Boolean[]{true, false};
+ inputDataClass.mArrBoxDouble = new Double[]{0.0, 1.0};
+ inputDataClass.mArrBoxLong = new Long[]{6L, 7L};
+ inputDataClass.mArrString = new String[]{"cat", "dog"};
+ inputDataClass.mBoxByteArr = new Byte[]{8, 9};
+ inputDataClass.mArrUnboxBoolean = new boolean[]{false, true};
+ inputDataClass.mArrUnboxByteArr = new byte[][]{{0, 1}, {2, 3}};
+ inputDataClass.mArrUnboxDouble = new double[]{1.0, 0.0};
+ inputDataClass.mArrUnboxLong = new long[]{7, 6};
+
+ Gift innerGift1 = new Gift();
+ innerGift1.mUri = "innerGift.uri1";
+ Gift innerGift2 = new Gift();
+ innerGift2.mUri = "innerGift.uri2";
+ inputDataClass.mLongCollection = Arrays.asList(inputDataClass.mArrBoxLong);
+ inputDataClass.mCollectBoolean = Arrays.asList(inputDataClass.mArrBoxBoolean);
+ inputDataClass.mCollectString = Arrays.asList(inputDataClass.mArrString);
+ inputDataClass.mCollectDouble = Arrays.asList(inputDataClass.mArrBoxDouble);
+ inputDataClass.mCollectByteArr = Arrays.asList(inputDataClass.mArrUnboxByteArr);
+ inputDataClass.mCollectGift = Arrays.asList(innerGift1, innerGift2);
+
+ inputDataClass.mString = "String";
+ inputDataClass.mBoxLong = 1L;
+ inputDataClass.mUnboxLong = 2L;
+ inputDataClass.mBoxDouble = 5.0;
+ inputDataClass.mUnboxDouble = 6.0;
+ inputDataClass.mBoxBoolean = true;
+ inputDataClass.mUnboxBoolean = false;
+ inputDataClass.mUnboxByteArr = new byte[]{1, 2, 3};
+
+ // Index the Gift document and query it.
+ checkIsBatchResultSuccess(mAppSearchManager.putDocuments(
+ new AppSearchManager.PutDocumentsRequest.Builder()
+ .addDataClass(inputDataClass).build()));
+ List<GenericDocument> searchResults = doQuery(mAppSearchManager, "");
+ assertThat(searchResults).hasSize(1);
+
+ // Create DataClassFactory for Gift.
+ DataClassFactoryRegistry registry = DataClassFactoryRegistry.getInstance();
+ DataClassFactory<Gift> factory = registry.getOrCreateFactory(Gift.class);
+
+ // Convert GenericDocument to Gift and check values.
+ Gift outputDataClass = factory.fromGenericDocument(searchResults.get((0)));
+ assertThat(outputDataClass).isEqualTo(inputDataClass);
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchManagerTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchManagerTest.java
index 6b7edaa..b971dce 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchManagerTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchManagerTest.java
@@ -20,6 +20,10 @@
import static androidx.appsearch.app.AppSearchManager.PutDocumentsRequest;
import static androidx.appsearch.app.AppSearchManager.RemoveDocumentsRequest;
import static androidx.appsearch.app.AppSearchManager.SetSchemaRequest;
+import static androidx.appsearch.app.AppSearchTestUtils.checkIsBatchResultSuccess;
+import static androidx.appsearch.app.AppSearchTestUtils.checkIsResultSuccess;
+import static androidx.appsearch.app.AppSearchTestUtils.doGet;
+import static androidx.appsearch.app.AppSearchTestUtils.doQuery;
import static com.google.common.truth.Truth.assertThat;
@@ -32,8 +36,6 @@
import androidx.appsearch.localbackend.LocalBackend;
import androidx.test.core.app.ApplicationProvider;
-import junit.framework.AssertionFailedError;
-
import org.junit.Before;
import org.junit.Test;
@@ -41,7 +43,6 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import java.util.concurrent.Future;
public class AppSearchManagerTest {
private AppSearchManager mDb1;
@@ -50,7 +51,7 @@
@Before
public void setUp() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
- LocalBackend backend = new LocalBackend.Builder(context).build().getResultValue();
+ LocalBackend backend = LocalBackend.getInstance(context).getResultValue();
mDb1 = checkIsResultSuccess(new AppSearchManager.Builder()
.setDatabaseName("testDb1").setBackend(backend).build());
mDb2 = checkIsResultSuccess(new AppSearchManager.Builder()
@@ -443,7 +444,7 @@
// Set number of results per page is 7.
SearchResults searchResults = mDb1.query("body",
new SearchSpec.Builder()
- .setTermMatchType(SearchSpec.TERM_MATCH_TYPE_EXACT_ONLY)
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
.setNumPerPage(7)
.build());
List<GenericDocument> documents = new ArrayList<>();
@@ -503,7 +504,7 @@
// Query only for Document
results = doQuery(mDb1, "body", new SearchSpec.Builder()
.setSchemaTypes("Generic")
- .setTermMatchType(SearchSpec.TERM_MATCH_TYPE_EXACT_ONLY)
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
.build());
assertThat(results).hasSize(1);
assertThat(results).containsExactly(inDoc);
@@ -547,7 +548,7 @@
results = doQuery(mDb1, "body",
new SearchSpec.Builder()
.setNamespaces("expectedNamespace")
- .setTermMatchType(SearchSpec.TERM_MATCH_TYPE_EXACT_ONLY)
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
.build());
assertThat(results).hasSize(1);
assertThat(results).containsExactly(expectedEmail);
@@ -623,15 +624,15 @@
SearchResults searchResults = mDb1.query("foo",
new SearchSpec.Builder()
.setSchemaTypes("Generic")
- .setNumToSnippet(1)
- .setNumMatchesPerProperty(1)
+ .setSnippetCount(1)
+ .setSnippetCountPerProperty(1)
.setMaxSnippetSize(10)
- .setTermMatchType(SearchSpec.TERM_MATCH_TYPE_PREFIX)
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
.build());
List<SearchResults.Result> results = checkIsResultSuccess(searchResults.getNextPage());
assertThat(results).hasSize(1);
- List<MatchInfo> matchInfos = results.get(0).getMatchInfo();
+ List<MatchInfo> matchInfos = results.get(0).getMatches();
assertThat(matchInfos).isNotNull();
assertThat(matchInfos).hasSize(1);
MatchInfo matchInfo = matchInfos.get(0);
@@ -1059,57 +1060,4 @@
() -> appSearchBuilder.setDatabaseName("/testDatabaseNameStartWith"));
assertThat(e).hasMessageThat().isEqualTo("Database name cannot contain '/'");
}
-
- private static List<GenericDocument> doGet(
- AppSearchManager instance, String namespace, String... uris) throws Exception {
- AppSearchBatchResult<String, GenericDocument> result = checkIsBatchResultSuccess(
- instance.getDocuments(new GetDocumentsRequest.Builder()
- .setNamespace(namespace).addUris(uris).build()));
- assertThat(result.getSuccesses()).hasSize(uris.length);
- assertThat(result.getFailures()).isEmpty();
- List<GenericDocument> list = new ArrayList<>(uris.length);
- for (String uri : uris) {
- list.add(result.getSuccesses().get(uri));
- }
- return list;
- }
-
- private List<GenericDocument> doQuery(
- AppSearchManager instance, String queryExpression, SearchSpec spec)
- throws Exception {
- SearchResults searchResults = instance.query(queryExpression, spec);
- List<SearchResults.Result> results = checkIsResultSuccess(searchResults.getNextPage());
- List<GenericDocument> documents = new ArrayList<>();
- while (results.size() > 0) {
- for (SearchResults.Result result : results) {
- documents.add(result.getDocument());
- }
- results = checkIsResultSuccess(searchResults.getNextPage());
- }
- return documents;
- }
-
- private List<GenericDocument> doQuery(AppSearchManager instance, String queryExpression)
- throws Exception {
- return doQuery(instance, queryExpression, new SearchSpec.Builder()
- .setTermMatchType(SearchSpec.TERM_MATCH_TYPE_EXACT_ONLY)
- .build());
- }
-
- private static <K, V> AppSearchBatchResult<K, V> checkIsBatchResultSuccess(
- Future<AppSearchBatchResult<K, V>> future) throws Exception {
- AppSearchBatchResult<K, V> result = future.get();
- if (!result.isSuccess()) {
- throw new AssertionFailedError("AppSearchBatchResult not successful: " + result);
- }
- return result;
- }
-
- private static <V> V checkIsResultSuccess(Future<AppSearchResult<V>> future) throws Exception {
- AppSearchResult<V> result = future.get();
- if (!result.isSuccess()) {
- throw new AssertionFailedError("AppSearchResult not successful: " + result);
- }
- return result.getResultValue();
- }
}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchSchemaTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchSchemaTest.java
index 217f825..01bc50a 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchSchemaTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchSchemaTest.java
@@ -25,105 +25,11 @@
import androidx.appsearch.exceptions.IllegalSchemaException;
import androidx.test.filters.SmallTest;
-import com.google.android.icing.proto.IndexingConfig;
-import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-import com.google.android.icing.proto.TermMatchType;
-
import org.junit.Test;
@SmallTest
public class AppSearchSchemaTest {
@Test
- public void testGetProto_Email() {
- AppSearchSchema emailSchema = new AppSearchSchema.Builder("Email")
- .addProperty(new PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(new PropertyConfig.Builder("body")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
-
- SchemaTypeConfigProto expectedEmailProto = SchemaTypeConfigProto.newBuilder()
- .setSchemaType("Email")
- .addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("subject")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setSchemaType("")
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- com.google.android.icing.proto.IndexingConfig.newBuilder()
- .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- )
- ).addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("body")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setSchemaType("")
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- com.google.android.icing.proto.IndexingConfig.newBuilder()
- .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- )
- ).build();
-
- assertThat(SchemaToProtoConverter.convert(emailSchema)).isEqualTo(expectedEmailProto);
- }
-
- @Test
- public void testGetProto_MusicRecording() {
- AppSearchSchema musicRecordingSchema = new AppSearchSchema.Builder("MusicRecording")
- .addProperty(new PropertyConfig.Builder("artist")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(new PropertyConfig.Builder("pubDate")
- .setDataType(PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_NONE)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_NONE)
- .build()
- ).build();
-
- SchemaTypeConfigProto expectedMusicRecordingProto = SchemaTypeConfigProto.newBuilder()
- .setSchemaType("MusicRecording")
- .addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("artist")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setSchemaType("")
- .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
- .setIndexingConfig(
- com.google.android.icing.proto.IndexingConfig.newBuilder()
- .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- )
- ).addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("pubDate")
- .setDataType(PropertyConfigProto.DataType.Code.INT64)
- .setSchemaType("")
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- com.google.android.icing.proto.IndexingConfig.newBuilder()
- .setTokenizerType(IndexingConfig.TokenizerType.Code.NONE)
- .setTermMatchType(TermMatchType.Code.UNKNOWN)
- )
- ).build();
-
- assertThat(SchemaToProtoConverter.convert(musicRecordingSchema))
- .isEqualTo(expectedMusicRecordingProto);
- }
-
- @Test
public void testInvalidEnums() {
PropertyConfig.Builder builder = new PropertyConfig.Builder("test");
assertThrows(IllegalArgumentException.class, () -> builder.setDataType(99));
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchTestUtils.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchTestUtils.java
new file mode 100644
index 0000000..0c0e417
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchTestUtils.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2020 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 androidx.appsearch.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import junit.framework.AssertionFailedError;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Future;
+
+public class AppSearchTestUtils {
+
+ public static <V> V checkIsResultSuccess(Future<AppSearchResult<V>> future) throws Exception {
+ AppSearchResult<V> result = future.get();
+ if (!result.isSuccess()) {
+ throw new AssertionFailedError("AppSearchResult not successful: " + result);
+ }
+ return result.getResultValue();
+ }
+
+ public static List<GenericDocument> doGet(
+ AppSearchManager instance, String namespace, String... uris) throws Exception {
+ AppSearchBatchResult<String, GenericDocument> result = checkIsBatchResultSuccess(
+ instance.getDocuments(new AppSearchManager.GetDocumentsRequest.Builder()
+ .setNamespace(namespace).addUris(uris).build()));
+ assertThat(result.getSuccesses()).hasSize(uris.length);
+ assertThat(result.getFailures()).isEmpty();
+ List<GenericDocument> list = new ArrayList<>(uris.length);
+ for (String uri : uris) {
+ list.add(result.getSuccesses().get(uri));
+ }
+ return list;
+ }
+
+ public static List<GenericDocument> doQuery(
+ AppSearchManager instance, String queryExpression, SearchSpec spec)
+ throws Exception {
+ SearchResults searchResults = instance.query(queryExpression, spec);
+ List<SearchResults.Result> results = checkIsResultSuccess(searchResults.getNextPage());
+ List<GenericDocument> documents = new ArrayList<>();
+ while (results.size() > 0) {
+ for (SearchResults.Result result : results) {
+ documents.add(result.getDocument());
+ }
+ results = checkIsResultSuccess(searchResults.getNextPage());
+ }
+ return documents;
+ }
+
+ public static List<GenericDocument> doQuery(AppSearchManager instance, String queryExpression)
+ throws Exception {
+ return doQuery(instance, queryExpression, new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ }
+
+ public static <K, V> AppSearchBatchResult<K, V> checkIsBatchResultSuccess(
+ Future<AppSearchBatchResult<K, V>> future) throws Exception {
+ AppSearchBatchResult<K, V> result = future.get();
+ if (!result.isSuccess()) {
+ throw new AssertionFailedError("AppSearchBatchResult not successful: " + result);
+ }
+ return result;
+ }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentTest.java
index 71e05dc..bfbb9fd 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentTest.java
@@ -22,26 +22,19 @@
import androidx.test.filters.SmallTest;
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.protobuf.ByteString;
-
import org.junit.Test;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-
@SmallTest
public class GenericDocumentTest {
private static final byte[] sByteArray1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
- private static final byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6};
+ private static final byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6, (byte) 7};
private static final GenericDocument sDocumentProperties1 = new GenericDocument
.Builder("sDocumentProperties1", "sDocumentPropertiesSchemaType1")
+ .setCreationTimestampMillis(12345L)
.build();
private static final GenericDocument sDocumentProperties2 = new GenericDocument
.Builder("sDocumentProperties2", "sDocumentPropertiesSchemaType2")
+ .setCreationTimestampMillis(6789L)
.build();
@Test
@@ -183,6 +176,49 @@
}
@Test
+ public void testDocument_ToString() throws Exception {
+ GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setProperty("longKey1", 1L, 2L, 3L)
+ .setProperty("doubleKey1", 1.0, 2.0, 3.0)
+ .setProperty("booleanKey1", true, false, true)
+ .setProperty("stringKey1", "String1", "String2", "String3")
+ .setProperty("byteKey1", sByteArray1, sByteArray2)
+ .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
+ .build();
+ String exceptedString = "{ key: 'creationTimestampMillis' value: 5 } "
+ + "{ key: 'namespace' value: } "
+ + "{ key: 'properties' value: "
+ + "{ key: 'booleanKey1' value: [ 'true' 'false' 'true' ] } "
+ + "{ key: 'byteKey1' value: "
+ + "{ key: 'byteArray' value: [ '1' '2' '3' ] } "
+ + "{ key: 'byteArray' value: [ '4' '5' '6' '7' ] } } "
+ + "{ key: 'documentKey1' value: [ '"
+ + "{ key: 'creationTimestampMillis' value: 12345 } "
+ + "{ key: 'namespace' value: } "
+ + "{ key: 'properties' value: } "
+ + "{ key: 'schemaType' value: sDocumentPropertiesSchemaType1 } "
+ + "{ key: 'score' value: 0 } "
+ + "{ key: 'ttlMillis' value: 0 } "
+ + "{ key: 'uri' value: sDocumentProperties1 } ' '"
+ + "{ key: 'creationTimestampMillis' value: 6789 } "
+ + "{ key: 'namespace' value: } "
+ + "{ key: 'properties' value: } "
+ + "{ key: 'schemaType' value: sDocumentPropertiesSchemaType2 } "
+ + "{ key: 'score' value: 0 } "
+ + "{ key: 'ttlMillis' value: 0 } "
+ + "{ key: 'uri' value: sDocumentProperties2 } ' ] } "
+ + "{ key: 'doubleKey1' value: [ '1.0' '2.0' '3.0' ] } "
+ + "{ key: 'longKey1' value: [ '1' '2' '3' ] } "
+ + "{ key: 'stringKey1' value: [ 'String1' 'String2' 'String3' ] } } "
+ + "{ key: 'schemaType' value: schemaType1 } "
+ + "{ key: 'score' value: 0 } "
+ + "{ key: 'ttlMillis' value: 0 } "
+ + "{ key: 'uri' value: uri1 } ";
+ assertThat(document.toString()).isEqualTo(exceptedString);
+ }
+
+ @Test
public void testDocumentGetValues_DifferentTypes() {
GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1")
.setScore(1)
@@ -215,50 +251,4 @@
assertThrows(
IllegalArgumentException.class, () -> builder.setProperty("test", new boolean[]{}));
}
-
- @Test
- public void testDocumentProtoPopulation() {
- GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setScore(1)
- .setTtlMillis(1L)
- .setNamespace("namespace")
- .setProperty("longKey1", 1L)
- .setProperty("doubleKey1", 1.0)
- .setProperty("booleanKey1", true)
- .setProperty("stringKey1", "test-value1")
- .setProperty("byteKey1", sByteArray1)
- .setProperty("documentKey1", sDocumentProperties1)
- .build();
-
- // Create the Document proto. Need to sort the property order by key.
- DocumentProto.Builder documentProtoBuilder = DocumentProto.newBuilder()
- .setUri("uri1")
- .setSchema("schemaType1")
- .setCreationTimestampMs(5L)
- .setScore(1)
- .setTtlMs(1L)
- .setNamespace("namespace");
- HashMap<String, PropertyProto.Builder> propertyProtoMap = new HashMap<>();
- propertyProtoMap.put("longKey1",
- PropertyProto.newBuilder().setName("longKey1").addInt64Values(1L));
- propertyProtoMap.put("doubleKey1",
- PropertyProto.newBuilder().setName("doubleKey1").addDoubleValues(1.0));
- propertyProtoMap.put("booleanKey1",
- PropertyProto.newBuilder().setName("booleanKey1").addBooleanValues(true));
- propertyProtoMap.put("stringKey1",
- PropertyProto.newBuilder().setName("stringKey1").addStringValues("test-value1"));
- propertyProtoMap.put("byteKey1",
- PropertyProto.newBuilder().setName("byteKey1").addBytesValues(
- ByteString.copyFrom(sByteArray1)));
- propertyProtoMap.put("documentKey1",
- PropertyProto.newBuilder().setName("documentKey1")
- .addDocumentValues(sDocumentProperties1.getProto()));
- List<String> sortedKey = new ArrayList<>(propertyProtoMap.keySet());
- Collections.sort(sortedKey);
- for (String key : sortedKey) {
- documentProtoBuilder.addProperties(propertyProtoMap.get(key));
- }
- assertThat(document.getProto()).isEqualTo(documentProtoBuilder.build());
- }
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBackend.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBackend.java
index 3e073a4..580f3da 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBackend.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBackend.java
@@ -16,9 +16,11 @@
package androidx.appsearch.app;
+import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
import java.io.Closeable;
import java.util.List;
@@ -31,8 +33,10 @@
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@WorkerThread
public interface AppSearchBackend {
/** Returns {@code true} if this backend has been successfully initialized. */
+ @AnyThread
boolean isInitialized();
/**
@@ -125,6 +129,7 @@
* Abstracts a returned search results object, where the pagination of the results can be
* implemented.
*/
+ @WorkerThread
interface BackendSearchResults extends Closeable {
/**
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchManager.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchManager.java
index 7291c563..4a08c79 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchManager.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchManager.java
@@ -98,8 +98,7 @@
}
/**
- * Connects to the AppSearch database per this builder's configuration, and asynchronously
- * returns the initialized instance.
+ * Asynchronously connects to the AppSearch backend and returns the initialized instance.
*/
@NonNull
public ListenableFuture<AppSearchResult<AppSearchManager>> build() {
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactory.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactory.java
index 9529a1b..5efb9a4 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactory.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactory.java
@@ -18,6 +18,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.exceptions.AppSearchException;
/**
* An interface for factories which can convert between data classes and {@link GenericDocument}.
@@ -37,17 +38,17 @@
/** Returns the schema for this data class. */
@NonNull
- AppSearchSchema getSchema();
+ AppSearchSchema getSchema() throws AppSearchException;
/**
* Converts an instance of the data class into a {@link androidx.appsearch.app.GenericDocument}.
*/
@NonNull
- GenericDocument toGenericDocument(@NonNull T dataClass);
+ GenericDocument toGenericDocument(@NonNull T dataClass) throws AppSearchException;
/**
* Converts a {@link androidx.appsearch.app.GenericDocument} into an instance of the data class.
*/
@NonNull
- T fromGenericDocument(@NonNull GenericDocument genericDoc);
+ T fromGenericDocument(@NonNull GenericDocument genericDoc) throws AppSearchException;
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactoryRegistry.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactoryRegistry.java
index b59e399..9166357 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactoryRegistry.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactoryRegistry.java
@@ -109,12 +109,19 @@
"Failed to find simple name for data class \"" + dataClass
+ "\". Perhaps it is anonymous?");
}
+
+ // Creates factory class name under the package.
+ // For a class Foo annotated with @AppSearchDocument, we will generated a
+ // $$__AppSearch__Foo.class under the package.
+ // For an inner class Foo.Bar annotated with @AppSearchDocument, we will generated a
+ // $$__AppSearch__Foo$$__Bar.class under the package.
String packageName = "";
if (pkg != null) {
packageName = pkg.getName() + ".";
- simpleName = simpleName.substring(packageName.length());
+ simpleName = simpleName.substring(packageName.length()).replace(".", "$$__");
}
String factoryClassName = packageName + GEN_CLASS_PREFIX + simpleName;
+
Class<?> factoryClass;
try {
factoryClass = Class.forName(factoryClassName);
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
index f7ef7c4..83d746f 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
@@ -17,22 +17,19 @@
package androidx.appsearch.app;
import android.annotation.SuppressLint;
+import android.os.Bundle;
import android.util.Log;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appsearch.exceptions.AppSearchException;
-import androidx.collection.ArrayMap;
import androidx.core.util.Preconditions;
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.protobuf.ByteString;
-
+import java.lang.reflect.Array;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Map;
+import java.util.Arrays;
+import java.util.Set;
/**
* Represents a document unit.
@@ -60,6 +57,21 @@
/** The maximum number of indexed properties a document can have. */
private static final int MAX_INDEXED_PROPERTIES = 16;
+ /** The default score of document. */
+ private static final int DEFAULT_SCORE = 0;
+
+ /** The default time-to-live in millisecond of a document, which is infinity. */
+ private static final long DEFAULT_TTL_MILLIS = 0L;
+
+ static final String SCHEMA_TYPE_FIELD = "schemaType";
+ static final String URI_FIELD = "uri";
+ static final String SCORE_FIELD = "score";
+ static final String TTL_MILLIS_FIELD = "ttlMillis";
+ static final String CREATION_TIMESTAMP_MILLIS_FIELD = "creationTimestampMillis";
+ static final String NAMESPACE_FIELD = "namespace";
+ static final String PROPERTIES_FIELD = "properties";
+ static final String BYTE_ARRAY_FIELD = "byteArray";
+
/**
* The maximum number of indexed properties a document can have.
*
@@ -72,30 +84,36 @@
return MAX_INDEXED_PROPERTIES;
}
- /**
- * Contains {@link GenericDocument} basic information (uri, schemaType etc) and properties
- * ordered by keys.
- */
+ /** Contains {@link GenericDocument} basic information (uri, schemaType etc).*/
@NonNull
- private final DocumentProto mProto;
+ final Bundle mBundle;
- /** Contains all properties in {@link #mProto} to support getting properties via keys. */
+ /** Contains all properties in {@link GenericDocument} to support getting properties via keys.*/
@NonNull
- private final Map<String, Object> mProperties;
+ final Bundle mProperties;
+
+ @NonNull
+ private final String mUri;
+ @NonNull
+ private final String mSchemaType;
+ private final long mCreationTimestampMillis;
+ @Nullable
+ private Integer mHashCode;
/**
- * Creates a new {@link GenericDocument}.
- * @param proto Contains {@link GenericDocument} basic information (uri, schemaType etc) and
- * properties ordered by keys.
- * @param propertiesMap Contains all properties in {@link #mProto} to support get properties
- * via keys.
+ * Rebuilds a {@link GenericDocument} by the a bundle.
+ * @param bundle Contains {@link GenericDocument} basic information (uri, schemaType etc) and
+ * a properties bundle contains all properties in {@link GenericDocument} to
+ * support getting properties via keys.
*/
- GenericDocument(@NonNull DocumentProto proto,
- @NonNull Map<String, Object> propertiesMap) {
- Preconditions.checkNotNull(proto);
- Preconditions.checkNotNull(propertiesMap);
- mProto = proto;
- mProperties = propertiesMap;
+ GenericDocument(@NonNull Bundle bundle) {
+ Preconditions.checkNotNull(bundle);
+ mBundle = bundle;
+ mProperties = Preconditions.checkNotNull(bundle.getParcelable(PROPERTIES_FIELD));
+ mUri = Preconditions.checkNotNull(mBundle.getString(URI_FIELD));
+ mSchemaType = Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
+ mCreationTimestampMillis = mBundle.getLong(CREATION_TIMESTAMP_MILLIS_FIELD,
+ System.currentTimeMillis());
}
/**
@@ -104,89 +122,30 @@
* <p>This method should be only used by constructor of a subclass.
*/
protected GenericDocument(@NonNull GenericDocument document) {
- this(document.mProto, document.mProperties);
- }
-
- GenericDocument(@NonNull DocumentProto documentProto) {
- this(documentProto, new ArrayMap<>());
- for (int i = 0; i < documentProto.getPropertiesCount(); i++) {
- PropertyProto property = documentProto.getProperties(i);
- String name = property.getName();
- if (property.getStringValuesCount() > 0) {
- String[] values = new String[property.getStringValuesCount()];
- for (int j = 0; j < values.length; j++) {
- values[j] = property.getStringValues(j);
- }
- mProperties.put(name, values);
- } else if (property.getInt64ValuesCount() > 0) {
- long[] values = new long[property.getInt64ValuesCount()];
- for (int j = 0; j < values.length; j++) {
- values[j] = property.getInt64Values(j);
- }
- mProperties.put(property.getName(), values);
- } else if (property.getDoubleValuesCount() > 0) {
- double[] values = new double[property.getDoubleValuesCount()];
- for (int j = 0; j < values.length; j++) {
- values[j] = property.getDoubleValues(j);
- }
- mProperties.put(property.getName(), values);
- } else if (property.getBooleanValuesCount() > 0) {
- boolean[] values = new boolean[property.getBooleanValuesCount()];
- for (int j = 0; j < values.length; j++) {
- values[j] = property.getBooleanValues(j);
- }
- mProperties.put(property.getName(), values);
- } else if (property.getBytesValuesCount() > 0) {
- byte[][] values = new byte[property.getBytesValuesCount()][];
- for (int j = 0; j < values.length; j++) {
- values[j] = property.getBytesValues(j).toByteArray();
- }
- mProperties.put(name, values);
- } else if (property.getDocumentValuesCount() > 0) {
- GenericDocument[] values =
- new GenericDocument[property.getDocumentValuesCount()];
- for (int j = 0; j < values.length; j++) {
- values[j] = new GenericDocument(property.getDocumentValues(j));
- }
- mProperties.put(name, values);
- } else {
- throw new IllegalStateException("Unknown type of value: " + name);
- }
- }
- }
-
- /**
- * Get the {@link DocumentProto} of the {@link GenericDocument}.
- *
- * <p>The {@link DocumentProto} contains {@link GenericDocument}'s basic information and all
- * properties ordered by keys.
- */
- @NonNull
- DocumentProto getProto() {
- return mProto;
+ this(document.mBundle);
}
/** Returns the URI of the {@link GenericDocument}. */
@NonNull
public String getUri() {
- return mProto.getUri();
+ return mUri;
}
/** Returns the namespace of the {@link GenericDocument}. */
@NonNull
public String getNamespace() {
- return mProto.getNamespace();
+ return mBundle.getString(NAMESPACE_FIELD, DEFAULT_NAMESPACE);
}
/** Returns the schema type of the {@link GenericDocument}. */
@NonNull
public String getSchemaType() {
- return mProto.getSchema();
+ return mSchemaType;
}
/** Returns the creation timestamp of the {@link GenericDocument}, in milliseconds. */
public long getCreationTimestampMillis() {
- return mProto.getCreationTimestampMs();
+ return mCreationTimestampMillis;
}
/**
@@ -196,7 +155,7 @@
* until the app is uninstalled.
*/
public long getTtlMillis() {
- return mProto.getTtlMs();
+ return mBundle.getLong(TTL_MILLIS_FIELD, DEFAULT_TTL_MILLIS);
}
/**
@@ -208,7 +167,7 @@
* <p>The default value is 0.
*/
public int getScore() {
- return mProto.getScore();
+ return mBundle.getInt(SCORE_FIELD, DEFAULT_SCORE);
}
/**
@@ -388,9 +347,28 @@
*/
@SuppressLint("ArrayReturn")
@Nullable
+ @SuppressWarnings("unchecked")
public byte[][] getPropertyBytesArray(@NonNull String key) {
Preconditions.checkNotNull(key);
- return getAndCastPropertyArray(key, byte[][].class);
+ ArrayList<Bundle> bundles = getAndCastPropertyArray(key, ArrayList.class);
+ if (bundles == null || bundles.size() == 0) {
+ return null;
+ }
+ byte[][] bytes = new byte[bundles.size()][];
+ for (int i = 0; i < bundles.size(); i++) {
+ Bundle bundle = bundles.get(i);
+ if (bundle == null) {
+ Log.e(TAG, "The inner bundle is null at " + i + ", for key: " + key);
+ continue;
+ }
+ byte[] innerBytes = bundle.getByteArray(BYTE_ARRAY_FIELD);
+ if (innerBytes == null) {
+ Log.e(TAG, "The bundle at " + i + " contains a null byte[].");
+ continue;
+ }
+ bytes[i] = innerBytes;
+ }
+ return bytes;
}
/**
@@ -404,7 +382,19 @@
@Nullable
public GenericDocument[] getPropertyDocumentArray(@NonNull String key) {
Preconditions.checkNotNull(key);
- return getAndCastPropertyArray(key, GenericDocument[].class);
+ Bundle[] bundles = getAndCastPropertyArray(key, Bundle[].class);
+ if (bundles == null || bundles.length == 0) {
+ return null;
+ }
+ GenericDocument[] documents = new GenericDocument[bundles.length];
+ for (int i = 0; i < bundles.length; i++) {
+ if (bundles[i] == null) {
+ Log.e(TAG, "The inner bundle is null at " + i + ", for key: " + key);
+ continue;
+ }
+ documents[i] = new GenericDocument(bundles[i]);
+ }
+ return documents;
}
/**
@@ -458,20 +448,203 @@
return false;
}
GenericDocument otherDocument = (GenericDocument) other;
- return this.mProto.equals(otherDocument.mProto);
+ return bundleEquals(this.mBundle, otherDocument.mBundle);
+ }
+
+ /**
+ * Deeply checks two bundle is equally or not.
+ * <p> Two bundle will be considered equally if they contains same content.
+ */
+ @SuppressWarnings("unchecked")
+ private static boolean bundleEquals(Bundle one, Bundle two) {
+ if (one.size() != two.size()) {
+ return false;
+ }
+ Set<String> keySetOne = one.keySet();
+ Object valueOne;
+ Object valueTwo;
+ // Bundle inherit its equals() from Object.java, which only compare their memory address.
+ // We should iterate all keys and check their presents and values in both bundle.
+ for (String key : keySetOne) {
+ valueOne = one.get(key);
+ valueTwo = two.get(key);
+ if (valueOne instanceof Bundle
+ && valueTwo instanceof Bundle
+ && !bundleEquals((Bundle) valueOne, (Bundle) valueTwo)) {
+ return false;
+ } else if (valueOne == null && (valueTwo != null || !two.containsKey(key))) {
+ // If we call bundle.get(key) when the 'key' doesn't actually exist in the
+ // bundle, we'll get back a null. So make sure that both values are null and
+ // both keys exist in the bundle.
+ return false;
+ } else if (valueOne instanceof boolean[]) {
+ if (!(valueTwo instanceof boolean[])
+ || !Arrays.equals((boolean[]) valueOne, (boolean[]) valueTwo)) {
+ return false;
+ }
+ } else if (valueOne instanceof long[]) {
+ if (!(valueTwo instanceof long[])
+ || !Arrays.equals((long[]) valueOne, (long[]) valueTwo)) {
+ return false;
+ }
+ } else if (valueOne instanceof double[]) {
+ if (!(valueTwo instanceof double[])
+ || !Arrays.equals((double[]) valueOne, (double[]) valueTwo)) {
+ return false;
+ }
+ } else if (valueOne instanceof Bundle[]) {
+ if (!(valueTwo instanceof Bundle[])) {
+ return false;
+ }
+ Bundle[] bundlesOne = (Bundle[]) valueOne;
+ Bundle[] bundlesTwo = (Bundle[]) valueTwo;
+ if (bundlesOne.length != bundlesTwo.length) {
+ return false;
+ }
+ for (int i = 0; i < bundlesOne.length; i++) {
+ if (!bundleEquals(bundlesOne[i], bundlesTwo[i])) {
+ return false;
+ }
+ }
+ } else if (valueOne instanceof ArrayList) {
+ if (!(valueTwo instanceof ArrayList)) {
+ return false;
+ }
+ ArrayList<Bundle> bundlesOne = (ArrayList<Bundle>) valueOne;
+ ArrayList<Bundle> bundlesTwo = (ArrayList<Bundle>) valueTwo;
+ if (bundlesOne.size() != bundlesTwo.size()) {
+ return false;
+ }
+ for (int i = 0; i < bundlesOne.size(); i++) {
+ if (!bundleEquals(bundlesOne.get(i), bundlesTwo.get(i))) {
+ return false;
+ }
+ }
+ } else if (valueOne instanceof Object[]) {
+ if (!(valueTwo instanceof Object[])
+ || !Arrays.equals((Object[]) valueOne, (Object[]) valueTwo)) {
+ return false;
+ }
+ }
+ }
+ return true;
}
@Override
public int hashCode() {
- // Hash only proto is sufficient here since all properties in mProperties are ordered by
- // keys and stored in proto.
- return mProto.hashCode();
+ if (mHashCode == null) {
+ mHashCode = bundleHashCode(mBundle);
+ }
+ return mHashCode;
+ }
+
+ /**
+ * Calculates the hash code for a bundle.
+ * <p> The hash code is only effected by the content in the bundle. Bundles will get
+ * consistent hash code if they have same content.
+ */
+ @SuppressWarnings("unchecked")
+ private static int bundleHashCode(Bundle bundle) {
+ int[] hashCodes = new int[bundle.size()];
+ int i = 0;
+ // Bundle inherit its hashCode() from Object.java, which only relative to their memory
+ // address. Bundle doesn't have an order, so we should iterate all keys and combine
+ // their value's hashcode into an array. And use the hashcode of the array to be
+ // the hashcode of the bundle.
+ for (String key : bundle.keySet()) {
+ Object value = bundle.get(key);
+ if (value instanceof boolean[]) {
+ hashCodes[i++] = Arrays.hashCode((boolean[]) value);
+ } else if (value instanceof long[]) {
+ hashCodes[i++] = Arrays.hashCode((long[]) value);
+ } else if (value instanceof double[]) {
+ hashCodes[i++] = Arrays.hashCode((double[]) value);
+ } else if (value instanceof String[]) {
+ hashCodes[i++] = Arrays.hashCode((Object[]) value);
+ } else if (value instanceof Bundle) {
+ hashCodes[i++] = bundleHashCode((Bundle) value);
+ } else if (value instanceof Bundle[]) {
+ Bundle[] bundles = (Bundle[]) value;
+ int[] innerHashCodes = new int[bundles.length];
+ for (int j = 0; j < innerHashCodes.length; j++) {
+ innerHashCodes[j] = bundleHashCode(bundles[j]);
+ }
+ hashCodes[i++] = Arrays.hashCode(innerHashCodes);
+ } else if (value instanceof ArrayList) {
+ ArrayList<Bundle> bundles = (ArrayList<Bundle>) value;
+ int[] innerHashCodes = new int[bundles.size()];
+ for (int j = 0; j < innerHashCodes.length; j++) {
+ innerHashCodes[j] = bundleHashCode(bundles.get(j));
+ }
+ hashCodes[i++] = Arrays.hashCode(innerHashCodes);
+ } else {
+ hashCodes[i++] = value.hashCode();
+ }
+ }
+ return Arrays.hashCode(hashCodes);
}
@Override
@NonNull
public String toString() {
- return mProto.toString();
+ return bundleToString(mBundle).toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ private static StringBuilder bundleToString(Bundle bundle) {
+ StringBuilder stringBuilder = new StringBuilder();
+ try {
+ final Set<String> keySet = bundle.keySet();
+ String[] keys = keySet.toArray(new String[0]);
+ // Sort keys to make output deterministic. We need a custom comparator to handle
+ // nulls (arbitrarily putting them first, similar to Comparator.nullsFirst, which is
+ // only available since N).
+ Arrays.sort(
+ keys,
+ (@Nullable String s1, @Nullable String s2) -> {
+ if (s1 == null) {
+ return s2 == null ? 0 : -1;
+ } else if (s2 == null) {
+ return 1;
+ } else {
+ return s1.compareTo(s2);
+ }
+ });
+ for (String key : keys) {
+ stringBuilder.append("{ key: '").append(key).append("' value: ");
+ Object valueObject = bundle.get(key);
+ if (valueObject == null) {
+ stringBuilder.append("<null>");
+ } else if (valueObject instanceof Bundle) {
+ stringBuilder.append(bundleToString((Bundle) valueObject));
+ } else if (valueObject.getClass().isArray()) {
+ stringBuilder.append("[ ");
+ for (int i = 0; i < Array.getLength(valueObject); i++) {
+ Object element = Array.get(valueObject, i);
+ stringBuilder.append("'");
+ if (element instanceof Bundle) {
+ stringBuilder.append(bundleToString((Bundle) element));
+ } else {
+ stringBuilder.append(Array.get(valueObject, i));
+ }
+ stringBuilder.append("' ");
+ }
+ stringBuilder.append("]");
+ } else if (valueObject instanceof ArrayList) {
+ for (Bundle innerBundle : (ArrayList<Bundle>) valueObject) {
+ stringBuilder.append(bundleToString(innerBundle));
+ }
+ } else {
+ stringBuilder.append(valueObject.toString());
+ }
+ stringBuilder.append(" } ");
+ }
+ } catch (RuntimeException e) {
+ // Catch any exceptions here since corrupt Bundles can throw different types of
+ // exceptions (e.g. b/38445840 & b/68937025).
+ stringBuilder.append("<error>");
+ }
+ return stringBuilder;
}
/**
@@ -481,8 +654,8 @@
*/
public static class Builder<BuilderType extends Builder> {
- private final Map<String, Object> mProperties = new ArrayMap<>();
- private final DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder();
+ private final Bundle mProperties = new Bundle();
+ private final Bundle mBundle = new Bundle();
private final BuilderType mBuilderTypeInstance;
private boolean mBuilt = false;
@@ -502,10 +675,15 @@
Preconditions.checkNotNull(uri);
Preconditions.checkNotNull(schemaType);
mBuilderTypeInstance = (BuilderType) this;
- mProtoBuilder.setUri(uri).setSchema(schemaType);
- mProtoBuilder.setNamespace(DEFAULT_NAMESPACE);
+ mBundle.putString(GenericDocument.URI_FIELD, uri);
+ mBundle.putString(GenericDocument.SCHEMA_TYPE_FIELD, schemaType);
+ mBundle.putString(GenericDocument.NAMESPACE_FIELD, DEFAULT_NAMESPACE);
// Set current timestamp for creation timestamp by default.
- setCreationTimestampMillis(System.currentTimeMillis());
+ mBundle.putLong(GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD,
+ System.currentTimeMillis());
+ mBundle.putLong(GenericDocument.TTL_MILLIS_FIELD, DEFAULT_TTL_MILLIS);
+ mBundle.putInt(GenericDocument.SCORE_FIELD, DEFAULT_SCORE);
+ mBundle.putBundle(PROPERTIES_FIELD, mProperties);
}
/**
@@ -515,7 +693,7 @@
*/
@NonNull
public BuilderType setNamespace(@NonNull String namespace) {
- mProtoBuilder.setNamespace(namespace);
+ mBundle.putString(GenericDocument.NAMESPACE_FIELD, namespace);
return mBuilderTypeInstance;
}
@@ -533,7 +711,7 @@
if (score < 0) {
throw new IllegalArgumentException("Document score cannot be negative.");
}
- mProtoBuilder.setScore(score);
+ mBundle.putInt(GenericDocument.SCORE_FIELD, score);
return mBuilderTypeInstance;
}
@@ -544,7 +722,8 @@
@NonNull
public BuilderType setCreationTimestampMillis(long creationTimestampMillis) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mProtoBuilder.setCreationTimestampMs(creationTimestampMillis);
+ mBundle.putLong(GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD,
+ creationTimestampMillis);
return mBuilderTypeInstance;
}
@@ -563,7 +742,7 @@
if (ttlMillis < 0) {
throw new IllegalArgumentException("Document ttlMillis cannot be negative.");
}
- mProtoBuilder.setTtlMs(ttlMillis);
+ mBundle.putLong(GenericDocument.TTL_MILLIS_FIELD, ttlMillis);
return mBuilderTypeInstance;
}
@@ -579,7 +758,7 @@
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(values);
- putInPropertyMap(key, values);
+ putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -595,7 +774,7 @@
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(values);
- putInPropertyMap(key, values);
+ putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -611,7 +790,7 @@
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(values);
- putInPropertyMap(key, values);
+ putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -627,7 +806,7 @@
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(values);
- putInPropertyMap(key, values);
+ putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -642,7 +821,7 @@
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(values);
- putInPropertyMap(key, values);
+ putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -658,11 +837,11 @@
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(values);
- putInPropertyMap(key, values);
+ putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
- private void putInPropertyMap(@NonNull String key, @NonNull String[] values)
+ private void putInPropertyBundle(@NonNull String key, @NonNull String[] values)
throws IllegalArgumentException {
validateRepeatedPropertyLength(key, values.length);
for (int i = 0; i < values.length; i++) {
@@ -674,37 +853,54 @@
+ MAX_STRING_LENGTH + ".");
}
}
- mProperties.put(key, values);
+ mProperties.putStringArray(key, values);
}
- private void putInPropertyMap(@NonNull String key, @NonNull boolean[] values) {
+ private void putInPropertyBundle(@NonNull String key, @NonNull boolean[] values) {
validateRepeatedPropertyLength(key, values.length);
- mProperties.put(key, values);
+ mProperties.putBooleanArray(key, values);
}
- private void putInPropertyMap(@NonNull String key, @NonNull double[] values) {
+ private void putInPropertyBundle(@NonNull String key, @NonNull double[] values) {
validateRepeatedPropertyLength(key, values.length);
- mProperties.put(key, values);
+ mProperties.putDoubleArray(key, values);
}
- private void putInPropertyMap(@NonNull String key, @NonNull long[] values) {
+ private void putInPropertyBundle(@NonNull String key, @NonNull long[] values) {
validateRepeatedPropertyLength(key, values.length);
- mProperties.put(key, values);
+ mProperties.putLongArray(key, values);
}
- private void putInPropertyMap(@NonNull String key, @NonNull byte[][] values) {
+ /**
+ * Converts and saves a byte[][] into {@link #mProperties}.
+ *
+ * <p>Bundle doesn't support for two dimension array byte[][], we are converting byte[][]
+ * into ArrayList<Bundle>, and each elements will contain a one dimension byte[].
+ */
+ private void putInPropertyBundle(@NonNull String key, @NonNull byte[][] values) {
validateRepeatedPropertyLength(key, values.length);
- mProperties.put(key, values);
+ ArrayList<Bundle> bundles = new ArrayList<>(values.length);
+ for (int i = 0; i < values.length; i++) {
+ if (values[i] == null) {
+ throw new IllegalArgumentException("The byte[] at " + i + " is null.");
+ }
+ Bundle bundle = new Bundle();
+ bundle.putByteArray(BYTE_ARRAY_FIELD, values[i]);
+ bundles.add(bundle);
+ }
+ mProperties.putParcelableArrayList(key, bundles);
}
- private void putInPropertyMap(@NonNull String key, @NonNull GenericDocument[] values) {
+ private void putInPropertyBundle(@NonNull String key, @NonNull GenericDocument[] values) {
+ validateRepeatedPropertyLength(key, values.length);
+ Bundle[] documentBundles = new Bundle[values.length];
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
throw new IllegalArgumentException("The document at " + i + " is null.");
}
+ documentBundles[i] = values[i].mBundle;
}
- validateRepeatedPropertyLength(key, values.length);
- mProperties.put(key, values);
+ mProperties.putParcelableArray(key, documentBundles);
}
private static void validateRepeatedPropertyLength(@NonNull String key, int length) {
@@ -722,48 +918,8 @@
@NonNull
public GenericDocument build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- // Build proto by sorting the keys in mProperties to exclude the influence of
- // order. Therefore documents will generate same proto as long as the contents are
- // same. Note that the order of repeated fields is still preserved.
- ArrayList<String> keys = new ArrayList<>(mProperties.keySet());
- Collections.sort(keys);
- for (int i = 0; i < keys.size(); i++) {
- String name = keys.get(i);
- Object values = mProperties.get(name);
- PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(name);
- if (values instanceof boolean[]) {
- for (boolean value : (boolean[]) values) {
- propertyProto.addBooleanValues(value);
- }
- } else if (values instanceof long[]) {
- for (long value : (long[]) values) {
- propertyProto.addInt64Values(value);
- }
- } else if (values instanceof double[]) {
- for (double value : (double[]) values) {
- propertyProto.addDoubleValues(value);
- }
- } else if (values instanceof String[]) {
- for (String value : (String[]) values) {
- propertyProto.addStringValues(value);
- }
- } else if (values instanceof GenericDocument[]) {
- for (GenericDocument value : (GenericDocument[]) values) {
- propertyProto.addDocumentValues(value.getProto());
- }
- } else if (values instanceof byte[][]) {
- for (byte[] value : (byte[][]) values) {
- propertyProto.addBytesValues(ByteString.copyFrom(value));
- }
- } else {
- throw new IllegalStateException(
- "Property \"" + name + "\" has unsupported value type \""
- + values.getClass().getSimpleName() + "\"");
- }
- mProtoBuilder.addProperties(propertyProto);
- }
mBuilt = true;
- return new GenericDocument(mProtoBuilder.build(), mProperties);
+ return new GenericDocument(mBundle);
}
}
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/MatchInfo.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/MatchInfo.java
index 97acf36..bdc79f1 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/MatchInfo.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/MatchInfo.java
@@ -66,9 +66,7 @@
* <p>{@link MatchInfo#getExactMatch()} returns "TestNameJr@gmail.com"
* <p>{@link MatchInfo#getSnippetPosition()} returns [0, 20]
* <p>{@link MatchInfo#getSnippet()} returns "TestNameJr@gmail.com"
- * @hide
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
// TODO(sidchhabra): Capture real snippet after integration with icingLib.
public final class MatchInfo {
// The path of the matching snippet property.
@@ -87,6 +85,7 @@
private MatchRange mExactMatchRange;
private MatchRange mWindowRange;
+
MatchInfo(@NonNull Bundle bundle, @NonNull GenericDocument document) {
mBundle = Preconditions.checkNotNull(bundle);
Preconditions.checkNotNull(document);
@@ -173,7 +172,7 @@
private CharSequence getSubstring(MatchRange range) {
return getFullText()
- .substring(range.getLower(), range.getUpper());
+ .substring(range.getStart(), range.getEnd());
}
/** Extracts the matching string from the document. */
@@ -200,33 +199,36 @@
*
*/
public static class MatchRange{
- private final int mUpper;
- private final int mLower;
+ private final int mEnd;
+ private final int mStart;
/**
* Creates a new immutable range.
- * <p> The endpoints are {@code [lower, upper)}; that is the range is bounded. {@code lower}
- * must be lesser or equal to {@code upper}.
+ * <p> The endpoints are {@code [start, end)}; that is the range is bounded. {@code start}
+ * must be lesser or equal to {@code end}.
*
- * @param lower The lower endpoint (inclusive)
- * @param upper The upper endpoint (exclusive)
+ * @param start The start point (inclusive)
+ * @param end The end point (exclusive)
+ * @hide
*/
- public MatchRange(int lower, int upper) {
- if (lower > upper) {
- throw new IllegalArgumentException("lower must be less than or equal to upper");
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public MatchRange(int start, int end) {
+ if (start > end) {
+ throw new IllegalArgumentException("Start point must be less than or equal to "
+ + "end point");
}
- mLower = lower;
- mUpper = upper;
+ mStart = start;
+ mEnd = end;
}
- /** Gets the lower endpoint (inclusive). */
- public int getLower() {
- return mLower;
+ /** Gets the start point (inclusive). */
+ public int getStart() {
+ return mStart;
}
- /** Gets the upper endpoint (exclusive). */
- public int getUpper() {
- return mUpper;
+ /** Gets the end point (exclusive). */
+ public int getEnd() {
+ return mEnd;
}
@Override
@@ -238,19 +240,19 @@
return false;
}
MatchRange otherMatchRange = (MatchRange) other;
- return this.getLower() == otherMatchRange.getLower()
- && this.getUpper() == otherMatchRange.getUpper();
+ return this.getStart() == otherMatchRange.getStart()
+ && this.getEnd() == otherMatchRange.getEnd();
}
@Override
@NonNull
public String toString() {
- return "MatchRange { lower: " + mLower + " , upper: " + mUpper + "}";
+ return "MatchRange { start: " + mStart + " , end: " + mEnd + "}";
}
@Override
public int hashCode() {
- return ObjectsCompat.hash(mLower, mUpper);
+ return ObjectsCompat.hash(mStart, mEnd);
}
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResults.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResults.java
index e055395..24dd6ad 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResults.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResults.java
@@ -20,7 +20,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
import androidx.concurrent.futures.ResolvableFuture;
import com.google.common.util.concurrent.ListenableFuture;
@@ -37,15 +36,14 @@
* request.
* <p>Should close this object after finish fetching results.
* <p>This class is not thread safe.
- * @hide
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public final class SearchResults implements Closeable {
private static final String TAG = "AppSearch-SearchResults";
private final ExecutorService mExecutorService;
private final AppSearchBackend.BackendSearchResults mBackendSearchResults;
+ /** @hide */
public SearchResults(@NonNull ExecutorService executorService,
@NonNull AppSearchBackend.BackendSearchResults backendSearchResults) {
mExecutorService = executorService;
@@ -97,17 +95,17 @@
/**
* Contains a list of Snippets that matched the request. Only populated when requested in
- * both {@link SearchSpec.Builder#setNumToSnippet}
- * and {@link SearchSpec.Builder#setNumMatchesPerProperty}.
+ * both {@link SearchSpec.Builder#setSnippetCount(int)}
+ * and {@link SearchSpec.Builder#setSnippetCountPerProperty(int)}.
*
- * @see #getMatchInfo()
+ * @see #getMatches()
*/
@Nullable
- private final List<MatchInfo> mMatchInfos;
+ private final List<MatchInfo> mMatches;
- Result(@NonNull GenericDocument document, @Nullable List<MatchInfo> matchInfos) {
+ Result(@NonNull GenericDocument document, @Nullable List<MatchInfo> matches) {
mDocument = document;
- mMatchInfos = matchInfos;
+ mMatches = matches;
}
/**
@@ -121,18 +119,18 @@
/**
* Contains a list of Snippets that matched the request. Only populated when requested in
- * both {@link SearchSpec.Builder#setNumToSnippet}
- * and {@link SearchSpec.Builder#setNumMatchesPerProperty}.
+ * both {@link SearchSpec.Builder#setSnippetCount(int)}
+ * and {@link SearchSpec.Builder#setSnippetCountPerProperty(int)}.
*
* @return List of matches based on {@link SearchSpec}, if snippeting is disabled and this
* method is called it will return {@code null}. Users can also restrict snippet population
- * using {@link SearchSpec.Builder#setNumToSnippet} and
- * {@link SearchSpec.Builder#setNumMatchesPerProperty}, for all results after that value
- * this method will return {@code null}.
+ * using {@link SearchSpec.Builder#setSnippetCount} and
+ * {@link SearchSpec.Builder#setSnippetCountPerProperty(int)}, for all results after that
+ * value this method will return {@code null}.
*/
@Nullable
- public List<MatchInfo> getMatchInfo() {
- return mMatchInfos;
+ public List<MatchInfo> getMatches() {
+ return mMatches;
}
}
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java
index 269af4b..a5cf9a2 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java
@@ -20,7 +20,6 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
import androidx.appsearch.exceptions.IllegalSearchSpecException;
import androidx.core.util.Preconditions;
@@ -30,9 +29,7 @@
/**
* This class represents the specification logic for AppSearch. It can be used to set the type of
* search, like prefix or exact only or apply filters to search for a specific schema type only etc.
- * @hide
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
// TODO(sidchhabra) : AddResultSpec fields for Snippets etc.
public final class SearchSpec {
@@ -42,10 +39,14 @@
static final String NUM_PER_PAGE_FIELD = "numPerPage";
static final String RANKING_STRATEGY_FIELD = "rankingStrategy";
static final String ORDER_FILED = "order";
- static final String NUM_TO_SNIPPET_FIELD = "numToSnippet";
- static final String NUM_MATCHED_PER_PROPERTY_FIELD = "numMatchedPerProperty";
+ static final String SNIPPET_COUNT_FIELD = "snippetCount";
+ static final String SNIPPET_COUNT_PER_PROPERTY_FIELD = "snippetCountPerProperty";
static final String MAX_SNIPPET_FIELD = "maxSnippet";
static final int DEFAULT_NUM_PER_PAGE = 10;
+ private static final int MAX_NUM_PER_PAGE = 10_000;
+ private static final int MAX_SNIPPET_COUNT = 10_000;
+ private static final int MAX_SNIPPET_PER_PROPERTY_COUNT = 10_000;
+ private static final int MAX_SNIPPET_SIZE_LIMIT = 10_000;
private final Bundle mBundle;
@@ -60,28 +61,34 @@
return mBundle;
}
- /** Term Match Type for the query. */
+ /**
+ * Term Match Type for the query.
+ * @hide
+ */
// NOTE: The integer values of these constants must match the proto enum constants in
// {@link com.google.android.icing.proto.SearchSpecProto.termMatchType}
@IntDef(value = {
- TERM_MATCH_TYPE_EXACT_ONLY,
- TERM_MATCH_TYPE_PREFIX
+ TERM_MATCH_EXACT_ONLY,
+ TERM_MATCH_PREFIX
})
@Retention(RetentionPolicy.SOURCE)
- public @interface TermMatchTypeCode {}
+ public @interface TermMatchCode {}
/**
* Query terms will only match exact tokens in the index.
* <p>Ex. A query term "foo" will only match indexed token "foo", and not "foot" or "football".
*/
- public static final int TERM_MATCH_TYPE_EXACT_ONLY = 1;
+ public static final int TERM_MATCH_EXACT_ONLY = 1;
/**
* Query terms will match indexed tokens when the query term is a prefix of the token.
* <p>Ex. A query term "foo" will match indexed tokens like "foo", "foot", and "football".
*/
- public static final int TERM_MATCH_TYPE_PREFIX = 2;
+ public static final int TERM_MATCH_PREFIX = 2;
- /** Ranking Strategy for query result.*/
+ /**
+ * Ranking Strategy for query result.
+ * @hide
+ */
// NOTE: The integer values of these constants must match the proto enum constants in
// {@link ScoringSpecProto.RankingStrategy.Code }
@IntDef(value = {
@@ -99,7 +106,10 @@
/** Ranked by document creation timestamps. */
public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2;
- /** Order for query result.*/
+ /**
+ * Order for query result.
+ * @hide
+ */
// NOTE: The integer values of these constants must match the proto enum constants in
// {@link ScoringSpecProto.Order.Code }
@IntDef(value = {
@@ -127,13 +137,13 @@
}
/**
- * Indicates how the query terms should match {@link TermMatchTypeCode} in the index.
+ * Indicates how the query terms should match {@code TermMatchCode} in the index.
*/
@NonNull
- public Builder setTermMatchType(@TermMatchTypeCode int termMatchTypeCode) {
+ public Builder setTermMatch(@TermMatchCode int termMatchTypeCode) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkArgumentInRange(termMatchTypeCode, TERM_MATCH_TYPE_EXACT_ONLY,
- TERM_MATCH_TYPE_PREFIX, "Term match type");
+ Preconditions.checkArgumentInRange(termMatchTypeCode, TERM_MATCH_EXACT_ONLY,
+ TERM_MATCH_PREFIX, "Term match type");
mBundle.putInt(TERM_MATCH_TYPE_FIELD, termMatchTypeCode);
return this;
}
@@ -166,14 +176,12 @@
/**
* Sets the number of results per page in the returned object.
- * <p> The default number of results per page is 10.
+ * <p> The default number of results per page is 10. And should be set in range [0, 10k].
*/
@NonNull
public SearchSpec.Builder setNumPerPage(int numPerPage) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- if (numPerPage <= 0) {
- throw new IllegalArgumentException("Invalid number per page :" + numPerPage);
- }
+ Preconditions.checkArgumentInRange(numPerPage, 0, MAX_NUM_PER_PAGE, "NumPerPage");
mBundle.putInt(NUM_PER_PAGE_FIELD, numPerPage);
return this;
}
@@ -203,28 +211,33 @@
}
/**
- * Only the first {@code numToSnippet} documents based on the ranking strategy
+ * Only the first {@code snippetCount} documents based on the ranking strategy
* will have snippet information provided.
* <p>If set to 0 (default), snippeting is disabled and
- * {@link SearchResults.Result#getMatchInfo} will return {@code null} for that result.
+ * {@link SearchResults.Result#getMatches} will return {@code null} for that result.
+ * <p>The value should be set in range[0, 10k].
*/
@NonNull
- public SearchSpec.Builder setNumToSnippet(int numToSnippet) {
+ public SearchSpec.Builder setSnippetCount(int snippetCount) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mBundle.putInt(NUM_TO_SNIPPET_FIELD, numToSnippet);
+ Preconditions.checkArgumentInRange(snippetCount, 0, MAX_SNIPPET_COUNT, "snippetCount");
+ mBundle.putInt(SNIPPET_COUNT_FIELD, snippetCount);
return this;
}
/**
- * Only the first {@code numMatchesPerProperty} matches for a every property of
+ * Only the first {@code matchesCountPerProperty} matches for a every property of
* {@link GenericDocument} will contain snippet information.
- * <p>If set to 0, snippeting is disabled and {@link SearchResults.Result#getMatchInfo}
+ * <p>If set to 0, snippeting is disabled and {@link SearchResults.Result#getMatches}
* will return {@code null} for that result.
+ * <p>The value should be set in range[0, 10k].
*/
@NonNull
- public SearchSpec.Builder setNumMatchesPerProperty(int numMatchesPerProperty) {
+ public SearchSpec.Builder setSnippetCountPerProperty(int snippetCountPerProperty) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mBundle.putInt(NUM_MATCHED_PER_PROPERTY_FIELD, numMatchesPerProperty);
+ Preconditions.checkArgumentInRange(snippetCountPerProperty,
+ 0, MAX_SNIPPET_PER_PROPERTY_COUNT, "snippetCountPerProperty");
+ mBundle.putInt(SNIPPET_COUNT_PER_PROPERTY_FIELD, snippetCountPerProperty);
return this;
}
@@ -237,10 +250,13 @@
* be returned. If matches enabled is also set to false, then snippeting is disabled.
* <p>Ex. {@code maxSnippetSize} = 16. "foo bar baz bat rat" with a query of "baz" will
* return a window of "bar baz bat" which is only 11 bytes long.
+ * <p>The value should be in range[0, 10k].
*/
@NonNull
public SearchSpec.Builder setMaxSnippetSize(int maxSnippetSize) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(
+ maxSnippetSize, 0, MAX_SNIPPET_SIZE_LIMIT, "maxSnippetSize");
mBundle.putInt(MAX_SNIPPET_FIELD, maxSnippetSize);
return this;
}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java
index a71e334..9ee924a 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java
@@ -72,8 +72,26 @@
JavaFile.builder(mOutputPackage, mOutputClass).build().writeTo(folder);
}
+ /**
+ * Creates factory class for any class annotated with
+ * {@link androidx.appsearch.annotation.AppSearchDocument}
+ * <p>Class Example 1:
+ * For a class Foo annotated with @AppSearchDocument, we will generated a
+ * $$__AppSearch__Foo.class under the output package.
+ * <p>Class Example 2:
+ * For an inner class Foo.Bar annotated with @AppSearchDocument, we will generated a
+ * $$__AppSearch__Foo$$__Bar.class under the output package.
+ */
private TypeSpec createClass() throws ProcessingException {
- String genClassName = GEN_CLASS_PREFIX + mModel.getClassElement().getSimpleName();
+ // Gets the full name of target class.
+ String qualifiedName = mModel.getClassElement().getQualifiedName().toString();
+ String packageName = mOutputPackage + ".";
+
+ // Creates the name of output class. $$__AppSearch__Foo for Foo, $$__AppSearch__Foo$$__Bar
+ // for inner class Foo.Bar.
+ String genClassName = GEN_CLASS_PREFIX
+ + qualifiedName.substring(packageName.length()).replace(".", "$$__");
+
TypeName genClassType = TypeName.get(mModel.getClassElement().asType());
TypeName factoryType = ParameterizedTypeName.get(
mHelper.getAppSearchClass("DataClassFactory"),
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java
index 91834ab..ec15c21 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java
@@ -32,6 +32,7 @@
import java.util.Map;
import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
@@ -74,7 +75,8 @@
.addModifiers(Modifier.PUBLIC)
.returns(classType)
.addAnnotation(Override.class)
- .addParameter(mHelper.getAppSearchClass("GenericDocument"), "genericDoc");
+ .addParameter(mHelper.getAppSearchClass("GenericDocument"), "genericDoc")
+ .addException(mHelper.getAppSearchExceptionClass());
unpackSpecialFields(methodBuilder);
@@ -115,8 +117,7 @@
// unboxing.
//
// 1b: ListCallArraysAsList
- // List contains String or GenericDocument.
- // We have to convert this from an array of String[] or GenericDocument[], but no
+ // List contains String. We have to convert this from an array of String[], but no
// conversion of the collection elements is needed. We can use Arrays#asList for this.
//
// 1c: ListForLoopCallFromGenericDocument
@@ -138,8 +139,7 @@
// of unboxing.
//
// 2b: ArrayUseDirectly
- // Array is of type String[], long[], double[], boolean[], byte[][] or
- // GenericDocument[].
+ // Array is of type String[], long[], double[], boolean[], byte[][].
// We can directly use this field with no conversion.
//
// 2c: ArrayForLoopCallFromGenericDocument
@@ -156,8 +156,7 @@
// Scenario 3: Single valued fields
// 3a: FieldUseDirectlyWithNullCheck
- // Field is of type String, Long, Integer, Double, Float, Boolean, byte[] or
- // GenericDocument.
+ // Field is of type String, Long, Integer, Double, Float, Boolean, byte[].
// We can use this field directly, after testing for null. The java compiler will box
// or unbox as needed.
//
@@ -201,12 +200,15 @@
List<? extends TypeMirror> genericTypes =
((DeclaredType) property.asType()).getTypeArguments();
TypeMirror propertyType = genericTypes.get(0);
+ ParameterizedTypeName listTypeName = ParameterizedTypeName.get(ClassName.get(List.class),
+ TypeName.get(propertyType));
- // TODO(b/156296904): Handle scenario 1c (ListForLoopCallFromGenericDocument)
CodeBlock.Builder builder = CodeBlock.builder();
- if (!tryListForLoopAssign(builder, fieldName, propertyName, propertyType) // 1a
+ if (!tryListForLoopAssign(builder, fieldName, propertyName, propertyType, listTypeName)// 1a
&& !tryListCallArraysAsList(
- builder, fieldName, propertyName, propertyType)) { // 1b
+ builder, fieldName, propertyName, propertyType, listTypeName) // 1b
+ && !tryListForLoopCallFromGenericDocument(
+ builder, fieldName, propertyName, propertyType, listTypeName)) { // 1c
// Scenario 1x
throw new ProcessingException(
"Unhandled in property type (1x): " + property.asType().toString(), property);
@@ -225,7 +227,8 @@
@NonNull CodeBlock.Builder method,
@NonNull String fieldName,
@NonNull String propertyName,
- @NonNull TypeMirror propertyType) {
+ @NonNull TypeMirror propertyType,
+ @NonNull ParameterizedTypeName listTypeName) {
Types typeUtil = mEnv.getTypeUtils();
CodeBlock.Builder body = CodeBlock.builder();
@@ -259,9 +262,7 @@
// Create the destination list
body.addStatement(
- "$T $NConv = null",
- ParameterizedTypeName.get(ClassName.get(List.class), TypeName.get(propertyType)),
- fieldName);
+ "$T $NConv = null", listTypeName, fieldName);
// If not null, iterate and assign
body
@@ -269,7 +270,7 @@
.addStatement(
"$NConv = new $T<>($NCopy.length)", fieldName, ArrayList.class, fieldName)
.add("for (int i = 0; i < $NCopy.length; i++) {\n", fieldName).indent()
- .addStatement("$NConv.set(i, $NCopy[i])", fieldName, fieldName)
+ .addStatement("$NConv.add($NCopy[i])", fieldName, fieldName)
.unindent().add("}\n")
.unindent().add("}\n");
method.add(body.build());
@@ -277,14 +278,14 @@
}
// 1b: ListCallArraysAsList
- // List contains String or GenericDocument.
- // We have to convert this from an array of String[] or GenericDocument[], but no
+ // List contains String. We have to convert this from an array of String[], but no
// conversion of the collection elements is needed. We can use Arrays#asList for this.
private boolean tryListCallArraysAsList(
@NonNull CodeBlock.Builder method,
@NonNull String fieldName,
@NonNull String propertyName,
- @NonNull TypeMirror propertyType) {
+ @NonNull TypeMirror propertyType,
+ @NonNull ParameterizedTypeName listTypeName) {
Types typeUtil = mEnv.getTypeUtils();
CodeBlock.Builder body = CodeBlock.builder();
@@ -293,20 +294,13 @@
"String[] $NCopy = genericDoc.getPropertyStringArray($S)",
fieldName, propertyName);
- } else if (typeUtil.isSameType(propertyType, mHelper.mGenericDocumentType)) {
- body.addStatement(
- "GenericDocument[] $NCopy = genericDoc.getPropertyDocumentArray($S)",
- fieldName, propertyName);
} else {
// This is not a type 1b list.
return false;
}
// Create the destination list
- body.addStatement(
- "$T $NConv = null",
- ParameterizedTypeName.get(ClassName.get(List.class), TypeName.get(propertyType)),
- fieldName);
+ body.addStatement("$T $NConv = null", listTypeName, fieldName);
// If not null, iterate and assign
body
@@ -318,6 +312,59 @@
return true;
}
+ // 1c: ListForLoopCallFromGenericDocument
+ // List contains a class which is annotated with @AppSearchDocument.
+ // We have to convert this from an array of GenericDocument[], by reading each element
+ // one-by-one and converting it through the standard conversion machinery.
+ private boolean tryListForLoopCallFromGenericDocument(
+ @NonNull CodeBlock.Builder method,
+ @NonNull String fieldName,
+ @NonNull String propertyName,
+ @NonNull TypeMirror propertyType,
+ @NonNull ParameterizedTypeName listTypeName) {
+ Types typeUtil = mEnv.getTypeUtils();
+ CodeBlock.Builder body = CodeBlock.builder();
+
+ Element element = typeUtil.asElement(propertyType);
+ if (element == null) {
+ // The propertyType is not an element, this is not a type 1c list.
+ return false;
+ }
+ try {
+ mHelper.getAnnotation(element, IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS);
+ } catch (ProcessingException e) {
+ // The propertyType doesn't have @AppSearchDocument annotation, this is not a type 1c
+ // list.
+ return false;
+ }
+
+ body.addStatement(
+ "GenericDocument[] $NCopy = genericDoc.getPropertyDocumentArray($S)",
+ fieldName, propertyName);
+
+ // Create the destination list
+ body.addStatement("$T $NConv = null", listTypeName, fieldName);
+
+ // If not null, iterate and assign
+ body.add("if ($NCopy != null) {\n", fieldName).indent();
+ body.addStatement("$T factory = $T.getInstance().getOrCreateFactory($T.class)",
+ ParameterizedTypeName.get(mHelper.getAppSearchClass("DataClassFactory"),
+ TypeName.get(propertyType)),
+ mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType);
+ body.addStatement("$NConv = new $T<>($NCopy.length)", fieldName, ArrayList.class,
+ fieldName);
+
+ body.add("for (int i = 0; i < $NCopy.length; i++) {\n", fieldName).indent();
+ body.addStatement("$NConv.add(factory.fromGenericDocument($NCopy[i]))", fieldName,
+ fieldName);
+ body.unindent().add("}\n");
+
+ body.unindent().add("}\n"); // if ($NCopy != null) {
+ method.add(body.build());
+
+ return true;
+ }
+
/**
* If the given field is an array, generates code to read it from a repeated GenericDocument
* property and returns true. If the field is not an array, returns false.
@@ -386,7 +433,7 @@
} else if (typeUtil.isSameType(propertyType, mHelper.mByteBoxType)) {
body.addStatement(
- "byte[][] $NCopy = genericDoc.getPropertyBytesArray($S)",
+ "byte[] $NCopy = genericDoc.getPropertyBytes($S)",
fieldName, propertyName);
} else {
@@ -411,8 +458,7 @@
}
// 2b: ArrayUseDirectly
- // Array is of type String[], long[], double[], boolean[], byte[][] or
- // GenericDocument[].
+ // Array is of type String[], long[], double[], boolean[], byte[][].
// We can directly use this field with no conversion.
private boolean tryArrayUseDirectly(
@NonNull CodeBlock.Builder method,
@@ -448,11 +494,6 @@
"byte[][] $NConv = genericDoc.getPropertyBytesArray($S)",
fieldName, propertyName);
- } else if (typeUtil.isSameType(propertyType, mHelper.mGenericDocumentType)) {
- body.addStatement(
- "GenericDocument[] $NConv = genericDoc.getPropertyDocumentArray($S)",
- fieldName, propertyName);
-
} else {
// This is not a type 2b array.
return false;
@@ -485,8 +526,7 @@
}
// 3a: FieldUseDirectlyWithNullCheck
- // Field is of type String, Long, Integer, Double, Float, Boolean, byte[] or
- // GenericDocument.
+ // Field is of type String, Long, Integer, Double, Float, Boolean, byte[].
// We can use this field directly, after testing for null. The java compiler will box
// or unbox as needed.
private boolean tryFieldUseDirectlyWithNullCheck(
@@ -527,11 +567,6 @@
"byte[][] $NCopy = genericDoc.getPropertyBytesArray($S)",
fieldName, propertyName);
- } else if (typeUtil.isSameType(propertyType, mHelper.mGenericDocumentType)) {
- body.addStatement(
- "GenericDocument[] $NCopy = genericDoc.getPropertyDocumentArray($S)",
- fieldName, propertyName);
-
} else {
// This is not a type 3a field
return false;
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
index eb9061c..0488796 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
@@ -42,6 +42,8 @@
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class IntrospectionHelper {
static final String APPSEARCH_PKG = "androidx.appsearch.app";
+ static final String APPSEARCH_EXCEPTION_PKG = "androidx.appsearch.exceptions";
+ static final String APPSEARCH_EXCEPTION_SIMPLE_NAME = "AppSearchException";
static final String APP_SEARCH_DOCUMENT_CLASS =
"androidx.appsearch.annotation.AppSearchDocument";
static final String URI_CLASS =
@@ -60,7 +62,6 @@
final TypeMirror mCollectionType;
final TypeMirror mListType;
final TypeMirror mStringType;
- final TypeMirror mGenericDocumentType;
final TypeMirror mIntegerBoxType;
final TypeMirror mIntPrimitiveType;
final TypeMirror mLongBoxType;
@@ -85,8 +86,6 @@
mCollectionType = elementUtil.getTypeElement(Collection.class.getName()).asType();
mListType = elementUtil.getTypeElement(List.class.getName()).asType();
mStringType = elementUtil.getTypeElement(String.class.getName()).asType();
- mGenericDocumentType = elementUtil.getTypeElement(
- getAppSearchClass("GenericDocument").toString()).asType();
mIntegerBoxType = elementUtil.getTypeElement(Integer.class.getName()).asType();
mIntPrimitiveType = typeUtil.unboxedType(mIntegerBoxType);
mLongBoxType = elementUtil.getTypeElement(Long.class.getName()).asType();
@@ -128,4 +127,8 @@
public ClassName getAppSearchClass(String clazz, String... nested) {
return ClassName.get(APPSEARCH_PKG, clazz, nested);
}
+
+ public ClassName getAppSearchExceptionClass() {
+ return ClassName.get(APPSEARCH_EXCEPTION_PKG, APPSEARCH_EXCEPTION_SIMPLE_NAME);
+ }
}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java
index b7fc514..0af8dc1 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java
@@ -65,12 +65,6 @@
.initializer("$S", mModel.getSchemaName())
.build());
- classBuilder.addField(
- FieldSpec.builder(mHelper.getAppSearchClass("AppSearchSchema"), "SCHEMA")
- .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
- .initializer(createSchemaInitializer())
- .build());
-
classBuilder.addMethod(
MethodSpec.methodBuilder("getSchemaType")
.addModifiers(Modifier.PUBLIC)
@@ -84,7 +78,8 @@
.addModifiers(Modifier.PUBLIC)
.returns(mHelper.getAppSearchClass("AppSearchSchema"))
.addAnnotation(Override.class)
- .addStatement("return SCHEMA")
+ .addException(mHelper.getAppSearchExceptionClass())
+ .addStatement("return $L", createSchemaInitializer())
.build());
}
@@ -172,6 +167,11 @@
}
codeBlock.add("\n.setDataType($T)", propertyTypeEnum);
+ if (isPropertyDocument) {
+ codeBlock.add("\n.setSchemaType($T.getInstance()"
+ + ".getOrCreateFactory($T.class).getSchemaType())",
+ mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType);
+ }
// Find property cardinality
ClassName cardinalityEnum;
if (repeated) {
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/ToGenericDocumentCodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/ToGenericDocumentCodeGenerator.java
index acaf09e..a6de552 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/ToGenericDocumentCodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/ToGenericDocumentCodeGenerator.java
@@ -29,6 +29,7 @@
import java.util.Map;
import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
@@ -71,7 +72,8 @@
.addModifiers(Modifier.PUBLIC)
.returns(mHelper.getAppSearchClass("GenericDocument"))
.addAnnotation(Override.class)
- .addParameter(classType, "dataClass");
+ .addParameter(classType, "dataClass")
+ .addException(mHelper.getAppSearchExceptionClass());
// Construct a new GenericDocument.Builder with the schema type and URI
methodBuilder.addStatement("$T builder =\nnew $T<>($L, SCHEMA_TYPE)",
@@ -204,10 +206,10 @@
((DeclaredType) property.asType()).getTypeArguments();
TypeMirror propertyType = genericTypes.get(0);
- // TODO(b/156296904): Handle scenario 1c (CollectionForLoopCallToGenericDocument)
- if (!tryCollectionForLoopAssign(body, fieldName, propertyName, propertyType) // 1a
- && !tryCollectionCallToArray(
- body, fieldName, propertyName, propertyType)) { // 1b
+ if (!tryCollectionForLoopAssign(body, fieldName, propertyName, propertyType) // 1a
+ && !tryCollectionCallToArray(body, fieldName, propertyName, propertyType) // 1b
+ && !tryCollectionForLoopCallToGenericDocument(
+ body, fieldName, propertyName, propertyType)) { // 1c
// Scenario 1x
throw new ProcessingException(
"Unhandled out property type (1x): " + property.asType().toString(), property);
@@ -270,8 +272,7 @@
}
// 1b: CollectionCallToArray
- // Collection contains String or GenericDocument.
- // We have to convert this into an array of String[] or GenericDocument[], but no
+ // Collection contains String. We have to convert this into an array of String[] or but no
// conversion of the collection elements is needed. We can use Collection#toArray for
// this.
private boolean tryCollectionCallToArray(
@@ -287,11 +288,6 @@
body.addStatement(
"String[] $NConv = $NCopy.toArray(new String[0])", fieldName, fieldName);
- } else if (typeUtil.isSameType(propertyType, mHelper.mGenericDocumentType)) {
- body.addStatement(
- "GenericDocument[] $NConv = $NCopy.toArray(new GenericDocument[0])", fieldName,
- fieldName);
-
} else {
// This is not a type 1b collection.
return false;
@@ -305,6 +301,52 @@
return true;
}
+ // 1c: CollectionForLoopCallToGenericDocument
+ // Collection contains a class which is annotated with @AppSearchDocument.
+ // We have to convert this into an array of GenericDocument[], by reading each element
+ // one-by-one and converting it through the standard conversion machinery.
+ private boolean tryCollectionForLoopCallToGenericDocument(
+ @NonNull CodeBlock.Builder method,
+ @NonNull String fieldName,
+ @NonNull String propertyName,
+ @NonNull TypeMirror propertyType) {
+ Types typeUtil = mEnv.getTypeUtils();
+ CodeBlock.Builder body = CodeBlock.builder()
+ .add("if ($NCopy != null) {\n", fieldName).indent();
+
+ Element element = typeUtil.asElement(propertyType);
+ if (element == null) {
+ // The propertyType is not an element, this is not a type 1c list.
+ return false;
+ }
+ try {
+ mHelper.getAnnotation(element, IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS);
+ } catch (ProcessingException e) {
+ // The propertyType doesn't have @AppSearchDocument annotation, this is not a type 1c
+ // list.
+ return false;
+ }
+
+ body.addStatement("GenericDocument[] $NConv = new GenericDocument[$NCopy.size()]",
+ fieldName, fieldName);
+ body.addStatement("$T factory = $T.getInstance().getOrCreateFactory($T.class)",
+ ParameterizedTypeName.get(mHelper.getAppSearchClass("DataClassFactory"),
+ TypeName.get(propertyType)),
+ mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType);
+
+ body.addStatement("int i = 0");
+ body.add("for ($T item : $NCopy) {\n", propertyType, fieldName).indent();
+ body.addStatement("$NConv[i++] = factory.toGenericDocument(item)", fieldName);
+
+ body.unindent().add("}\n");
+
+ body.addStatement("builder.setProperty($S, $NConv)", propertyName, fieldName)
+ .unindent().add("}\n"); // if ($NCopy != null) {
+
+ method.add(body.build());
+ return true;
+ }
+
/**
* If the given field is an array, generates code to read it and convert it into a form suitable
* for GenericDocument and returns true. If the field is not an array, returns false.
@@ -400,8 +442,7 @@
}
// 2b: ArrayUseDirectly
- // Array is of type String[], long[], double[], boolean[], byte[][] or
- // GenericDocument[].
+ // Array is of type String[], long[], double[], boolean[], byte[][].
// We can directly use this field with no conversion.
private boolean tryArrayUseDirectly(
@NonNull CodeBlock.Builder method,
@@ -416,8 +457,7 @@
&& !typeUtil.isSameType(propertyType, mHelper.mLongPrimitiveType)
&& !typeUtil.isSameType(propertyType, mHelper.mDoublePrimitiveType)
&& !typeUtil.isSameType(propertyType, mHelper.mBooleanPrimitiveType)
- && !typeUtil.isSameType(propertyType, mHelper.mBytePrimitiveArrayType)
- && !typeUtil.isSameType(propertyType, mHelper.mGenericDocumentType)) {
+ && !typeUtil.isSameType(propertyType, mHelper.mBytePrimitiveArrayType)) {
// This is not a type 2b array.
return false;
}
@@ -453,8 +493,7 @@
}
// 3a: FieldUseDirectlyWithNullCheck
- // Field is of type String, Long, Integer, Double, Float, Boolean, byte[] or
- // GenericDocument.
+ // Field is of type String, Long, Integer, Double, Float, Boolean, byte[].
// We can use this field directly, after testing for null. The java compiler will box
// or unbox as needed.
private boolean tryFieldUseDirectlyWithNullCheck(
@@ -478,8 +517,7 @@
&& !typeUtil.isSameType(propertyType, mHelper.mDoubleBoxType)
&& !typeUtil.isSameType(propertyType, mHelper.mFloatBoxType)
&& !typeUtil.isSameType(propertyType, mHelper.mBooleanBoxType)
- && !typeUtil.isSameType(propertyType, mHelper.mBytePrimitiveArrayType)
- && !typeUtil.isSameType(propertyType, mHelper.mGenericDocumentType)) {
+ && !typeUtil.isSameType(propertyType, mHelper.mBytePrimitiveArrayType)) {
// This is not a type 3a field
return false;
}
diff --git a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
index 1270853..fc10040 100644
--- a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
+++ b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
@@ -218,7 +218,7 @@
+ " void setPrice(int n) {}\n"
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
}
@Test
@@ -293,7 +293,7 @@
+ " void setPrice(int n) {}\n"
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
}
@Test
@@ -362,7 +362,7 @@
+ " public boolean getDog() { return dog; }\n"
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
}
@Test
@@ -373,7 +373,7 @@
+ " @AppSearchDocument.Uri String uri;\n"
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
}
@Test
@@ -389,7 +389,7 @@
+ " @AppSearchDocument.Property byte[] byteArray;\n"
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
}
@Test
@@ -405,7 +405,7 @@
+ " @AppSearchDocument.Property(required=false) Float noReq;\n"
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
}
@Test
@@ -426,7 +426,7 @@
//+ " @AppSearchDocument.Property Gift documentProp;\n"
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
}
@Test
@@ -442,7 +442,7 @@
+ " @AppSearchDocument.Property(tokenizerType=1) String tokPlain;\n"
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
}
@Test
@@ -473,7 +473,7 @@
+ " @AppSearchDocument.Property(indexingType=2) String indexPrefix;\n"
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
}
@Test
@@ -500,7 +500,7 @@
+ " @AppSearchDocument.Property(name=\"newName\") String oldName;\n"
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
}
@Test
@@ -521,8 +521,7 @@
+ " @Property Collection<Boolean> collectBoolean;\n" // 1a
+ " @Property Collection<byte[]> collectByteArr;\n" // 1a
+ " @Property Collection<String> collectString;\n" // 1b
- + " @Property Collection<GenericDocument> collectGenDoc;\n" // 1b
- //+ " @Property Collection<Gift> collectGift;\n" // 1c
+ + " @Property Collection<Gift> collectGift;\n" // 1c
+ "\n"
+ " // Arrays\n"
+ " @Property Long[] arrBoxLong;\n" // 2a
@@ -538,7 +537,6 @@
+ " @Property byte[][] arrUnboxByteArr;\n" // 2b
+ " @Property Byte[] boxByteArr;\n" // 2a
+ " @Property String[] arrString;\n" // 2b
- + " @Property GenericDocument[] arrGenDoc;\n" // 2b
//+ " @Property Gift[] arrGift;\n" // 2c
+ "\n"
+ " // Single values\n"
@@ -554,11 +552,10 @@
+ " @Property Boolean boxBoolean;\n" // 3a
+ " @Property boolean unboxBoolean;\n" // 3b
+ " @Property byte[] unboxByteArr;\n" // 3a
- + " @Property GenericDocument genDocument;\n" // 3a
//+ " @Property Gift gift;\n" // 3c
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
}
@Test
@@ -637,7 +634,7 @@
+ " @AppSearchDocument.Score int score;\n"
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
}
@Test
@@ -664,7 +661,23 @@
+ " public void setPrice(int price) { this.price = price; }\n"
+ "}\n");
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
- checkEqualsGolden();
+ checkEqualsGolden("Gift.java");
+ }
+
+ @Test
+ public void testInnerClass() throws Exception {
+ Compilation compilation = compile(
+ "import java.util.*;\n"
+ + "import androidx.appsearch.app.GenericDocument;\n"
+ + "public class Gift {\n"
+ + " @AppSearchDocument\n"
+ + " public static class InnerGift{\n"
+ + " @AppSearchDocument.Uri String uri;\n"
+ + " @Property String[] arrString;\n" // 2b
+ + " }\n"
+ + "}\n");
+ CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+ checkEqualsGolden("Gift$$__InnerGift.java");
}
private Compilation compile(String classBody) {
@@ -692,7 +705,7 @@
.compile(jfo);
}
- private void checkEqualsGolden() throws IOException {
+ private void checkEqualsGolden(String className) throws IOException {
// Get the expected file contents
String goldenResPath = "goldens/" + mTestName.getMethodName() + ".JAVA";
String expected = "";
@@ -707,7 +720,7 @@
// Get the actual file contents
File actualPackageDir = new File(mGenFilesDir, "com/example/appsearch");
- File actualPath = new File(actualPackageDir, CodeGenerator.GEN_CLASS_PREFIX + "Gift.java");
+ File actualPath = new File(actualPackageDir, CodeGenerator.GEN_CLASS_PREFIX + className);
Truth.assertWithMessage("Path " + actualPath + " is not a file")
.that(actualPath.isFile()).isTrue();
String actual = Files.asCharSource(actualPath, StandardCharsets.UTF_8).read();
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSingleTypes.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSingleTypes.JAVA
index da9aacc..299cccf 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSingleTypes.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSingleTypes.JAVA
@@ -3,6 +3,7 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Boolean;
import java.lang.Double;
import java.lang.Float;
@@ -14,63 +15,61 @@
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "Gift";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("stringProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("integerProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("longProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("floatProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("doubleProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("booleanProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("bytesProp")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("stringProp")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("integerProp")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("longProp")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("floatProp")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("doubleProp")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("booleanProp")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("bytesProp")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
String stringPropCopy = dataClass.stringProp;
@@ -105,7 +104,7 @@
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
String[] stringPropCopy = genericDoc.getPropertyStringArray("stringProp");
String stringPropConv = null;
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Field.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Field.JAVA
index 3843c23..278b64f 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Field.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Field.JAVA
@@ -3,33 +3,32 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "Gift";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
String namespaceCopy = dataClass.namespace;
@@ -44,7 +43,7 @@
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
String namespaceConv = genericDoc.getNamespace();
long creationTsConv = genericDoc.getCreationTimestampMillis();
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Getter.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Getter.JAVA
index 1cf34f5..992674e 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Getter.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Getter.JAVA
@@ -3,33 +3,32 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "Gift";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.getUri(), SCHEMA_TYPE);
builder.setCreationTimestampMillis(dataClass.getCreationTs());
@@ -40,7 +39,7 @@
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
long creationTsConv = genericDoc.getCreationTimestampMillis();
long ttlMsConv = genericDoc.getTtlMillis();
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCardinality.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCardinality.JAVA
index 3fc783e..732beed 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCardinality.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCardinality.JAVA
@@ -3,6 +3,7 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Float;
import java.lang.Override;
import java.lang.String;
@@ -12,45 +13,43 @@
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "Gift";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatReq")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatNoReq")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("req")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("noReq")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatReq")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatNoReq")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("req")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("noReq")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
List<String> repeatReqCopy = dataClass.repeatReq;
@@ -75,7 +74,7 @@
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
String[] repeatReqCopy = genericDoc.getPropertyStringArray("repeatReq");
List<String> repeatReqConv = null;
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testDifferentTypeName.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testDifferentTypeName.JAVA
index 3d696f0..2c55500 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testDifferentTypeName.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testDifferentTypeName.JAVA
@@ -3,34 +3,33 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "DifferentType";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
return builder.build();
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
Gift dataClass = new Gift();
dataClass.uri = uriConv;
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testIndexingType.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testIndexingType.JAVA
index 43dc25a..255d72c 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testIndexingType.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testIndexingType.JAVA
@@ -3,45 +3,44 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "Gift";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexNone")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexExact")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexPrefix")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build())
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexNone")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexExact")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexPrefix")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .build())
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
String indexNoneCopy = dataClass.indexNone;
@@ -60,7 +59,7 @@
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
String[] indexNoneCopy = genericDoc.getPropertyStringArray("indexNone");
String indexNoneConv = null;
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testInnerClass.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testInnerClass.JAVA
new file mode 100644
index 0000000..9baf8f1
--- /dev/null
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testInnerClass.JAVA
@@ -0,0 +1,50 @@
+package com.example.appsearch;
+
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
+import java.lang.Override;
+import java.lang.String;
+
+public class $$__AppSearch__Gift$$__InnerGift implements DataClassFactory<Gift.InnerGift> {
+ private static final String SCHEMA_TYPE = "InnerGift";
+
+ @Override
+ public String getSchemaType() {
+ return SCHEMA_TYPE;
+ }
+
+ @Override
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrString")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
+ }
+
+ @Override
+ public GenericDocument toGenericDocument(Gift.InnerGift dataClass) throws AppSearchException {
+ GenericDocument.Builder<?> builder =
+ new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
+ String[] arrStringCopy = dataClass.arrString;
+ if (arrStringCopy != null) {
+ builder.setProperty("arrString", arrStringCopy);
+ }
+ return builder.build();
+ }
+
+ @Override
+ public Gift.InnerGift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
+ String uriConv = genericDoc.getUri();
+ String[] arrStringConv = genericDoc.getPropertyStringArray("arrString");
+ Gift.InnerGift dataClass = new Gift.InnerGift();
+ dataClass.uri = uriConv;
+ dataClass.arrString = arrStringConv;
+ return dataClass;
+ }
+}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testPropertyName.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testPropertyName.JAVA
index 9140e149..c72e2a4 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testPropertyName.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testPropertyName.JAVA
@@ -3,33 +3,32 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "Gift";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("newName")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("newName")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
String oldNameCopy = dataClass.oldName;
@@ -40,7 +39,7 @@
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
String[] oldNameCopy = genericDoc.getPropertyStringArray("newName");
String oldNameConv = null;
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRead_MultipleGetters.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRead_MultipleGetters.JAVA
index fdbae72..66c7ed7 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRead_MultipleGetters.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRead_MultipleGetters.JAVA
@@ -3,33 +3,32 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "Gift";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
builder.setProperty("price", dataClass.getPrice());
@@ -37,7 +36,7 @@
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
int priceConv = genericDoc.getPropertyLong("price");
Gift dataClass = new Gift();
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRepeatedFields.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRepeatedFields.JAVA
index b0cece9..7ceb65d 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRepeatedFields.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRepeatedFields.JAVA
@@ -3,6 +3,7 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Integer;
import java.lang.Override;
import java.lang.String;
@@ -14,45 +15,43 @@
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "Gift";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("listOfString")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("setOfInt")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatedByteArray")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("byteArray")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("listOfString")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("setOfInt")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatedByteArray")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("byteArray")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
List<String> listOfStringCopy = dataClass.listOfString;
@@ -81,7 +80,7 @@
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
String[] listOfStringCopy = genericDoc.getPropertyStringArray("listOfString");
List<String> listOfStringConv = null;
@@ -93,7 +92,7 @@
if (setOfIntCopy != null) {
setOfIntConv = new ArrayList<>(setOfIntCopy.length);
for (int i = 0; i < setOfIntCopy.length; i++) {
- setOfIntConv.set(i, setOfIntCopy[i]);
+ setOfIntConv.add(setOfIntCopy[i]);
}
}
byte[][] repeatedByteArrayConv = genericDoc.getPropertyBytesArray("repeatedByteArray");
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuccessSimple.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuccessSimple.JAVA
index 66a5b03..ca57ea7 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuccessSimple.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuccessSimple.JAVA
@@ -3,45 +3,44 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "Gift";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("cat")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("dog")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("cat")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("dog")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
builder.setProperty("price", dataClass.price);
@@ -51,7 +50,7 @@
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
int priceConv = genericDoc.getPropertyLong("price");
boolean catConv = genericDoc.getPropertyBoolean("cat");
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testToGenericDocument_AllSupportedTypes.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testToGenericDocument_AllSupportedTypes.JAVA
index 35b09a1..9e3c236 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testToGenericDocument_AllSupportedTypes.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testToGenericDocument_AllSupportedTypes.JAVA
@@ -2,7 +2,9 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DataClassFactoryRegistry;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Boolean;
import java.lang.Byte;
import java.lang.Double;
@@ -19,231 +21,218 @@
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "Gift";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectLong")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectInteger")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectDouble")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectFloat")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectBoolean")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectByteArr")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectString")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectGenDoc")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxLong")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxLong")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxInteger")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxInt")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxDouble")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxDouble")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxFloat")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxFloat")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxBoolean")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxBoolean")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxByteArr")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxByteArr")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrString")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrGenDoc")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("string")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxLong")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxLong")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxInteger")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxInt")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxDouble")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxDouble")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxFloat")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxFloat")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxBoolean")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxBoolean")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxByteArr")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("genDocument")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectLong")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectInteger")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectDouble")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectFloat")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectBoolean")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectByteArr")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectString")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectGift")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
+ .setSchemaType(DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class).getSchemaType())
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxLong")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxLong")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxInteger")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxInt")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxDouble")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxDouble")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxFloat")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxFloat")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxBoolean")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxBoolean")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxByteArr")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxByteArr")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrString")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("string")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxLong")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxLong")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxInteger")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxInt")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxDouble")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxDouble")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxFloat")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxFloat")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxBoolean")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxBoolean")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxByteArr")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
Collection<Long> collectLongCopy = dataClass.collectLong;
@@ -305,10 +294,15 @@
String[] collectStringConv = collectStringCopy.toArray(new String[0]);
builder.setProperty("collectString", collectStringConv);
}
- Collection<GenericDocument> collectGenDocCopy = dataClass.collectGenDoc;
- if (collectGenDocCopy != null) {
- GenericDocument[] collectGenDocConv = collectGenDocCopy.toArray(new GenericDocument[0]);
- builder.setProperty("collectGenDoc", collectGenDocConv);
+ Collection<Gift> collectGiftCopy = dataClass.collectGift;
+ if (collectGiftCopy != null) {
+ GenericDocument[] collectGiftConv = new GenericDocument[collectGiftCopy.size()];
+ DataClassFactory<Gift> factory = DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class);
+ int i = 0;
+ for (Gift item : collectGiftCopy) {
+ collectGiftConv[i++] = factory.toGenericDocument(item);
+ }
+ builder.setProperty("collectGift", collectGiftConv);
}
Long[] arrBoxLongCopy = dataClass.arrBoxLong;
if (arrBoxLongCopy != null) {
@@ -394,10 +388,6 @@
if (arrStringCopy != null) {
builder.setProperty("arrString", arrStringCopy);
}
- GenericDocument[] arrGenDocCopy = dataClass.arrGenDoc;
- if (arrGenDocCopy != null) {
- builder.setProperty("arrGenDoc", arrGenDocCopy);
- }
String stringCopy = dataClass.string;
if (stringCopy != null) {
builder.setProperty("string", stringCopy);
@@ -431,22 +421,18 @@
if (unboxByteArrCopy != null) {
builder.setProperty("unboxByteArr", unboxByteArrCopy);
}
- GenericDocument genDocumentCopy = dataClass.genDocument;
- if (genDocumentCopy != null) {
- builder.setProperty("genDocument", genDocumentCopy);
- }
return builder.build();
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
long[] collectLongCopy = genericDoc.getPropertyLongArray("collectLong");
List<Long> collectLongConv = null;
if (collectLongCopy != null) {
collectLongConv = new ArrayList<>(collectLongCopy.length);
for (int i = 0; i < collectLongCopy.length; i++) {
- collectLongConv.set(i, collectLongCopy[i]);
+ collectLongConv.add(collectLongCopy[i]);
}
}
long[] collectIntegerCopy = genericDoc.getPropertyLongArray("collectInteger");
@@ -454,7 +440,7 @@
if (collectIntegerCopy != null) {
collectIntegerConv = new ArrayList<>(collectIntegerCopy.length);
for (int i = 0; i < collectIntegerCopy.length; i++) {
- collectIntegerConv.set(i, collectIntegerCopy[i]);
+ collectIntegerConv.add(collectIntegerCopy[i]);
}
}
double[] collectDoubleCopy = genericDoc.getPropertyDoubleArray("collectDouble");
@@ -462,7 +448,7 @@
if (collectDoubleCopy != null) {
collectDoubleConv = new ArrayList<>(collectDoubleCopy.length);
for (int i = 0; i < collectDoubleCopy.length; i++) {
- collectDoubleConv.set(i, collectDoubleCopy[i]);
+ collectDoubleConv.add(collectDoubleCopy[i]);
}
}
double[] collectFloatCopy = genericDoc.getPropertyDoubleArray("collectFloat");
@@ -470,7 +456,7 @@
if (collectFloatCopy != null) {
collectFloatConv = new ArrayList<>(collectFloatCopy.length);
for (int i = 0; i < collectFloatCopy.length; i++) {
- collectFloatConv.set(i, collectFloatCopy[i]);
+ collectFloatConv.add(collectFloatCopy[i]);
}
}
boolean[] collectBooleanCopy = genericDoc.getPropertyBooleanArray("collectBoolean");
@@ -478,7 +464,7 @@
if (collectBooleanCopy != null) {
collectBooleanConv = new ArrayList<>(collectBooleanCopy.length);
for (int i = 0; i < collectBooleanCopy.length; i++) {
- collectBooleanConv.set(i, collectBooleanCopy[i]);
+ collectBooleanConv.add(collectBooleanCopy[i]);
}
}
byte[][] collectByteArrCopy = genericDoc.getPropertyBytesArray("collectByteArr");
@@ -486,7 +472,7 @@
if (collectByteArrCopy != null) {
collectByteArrConv = new ArrayList<>(collectByteArrCopy.length);
for (int i = 0; i < collectByteArrCopy.length; i++) {
- collectByteArrConv.set(i, collectByteArrCopy[i]);
+ collectByteArrConv.add(collectByteArrCopy[i]);
}
}
String[] collectStringCopy = genericDoc.getPropertyStringArray("collectString");
@@ -494,10 +480,14 @@
if (collectStringCopy != null) {
collectStringConv = Arrays.asList(collectStringCopy);
}
- GenericDocument[] collectGenDocCopy = genericDoc.getPropertyDocumentArray("collectGenDoc");
- List<GenericDocument> collectGenDocConv = null;
- if (collectGenDocCopy != null) {
- collectGenDocConv = Arrays.asList(collectGenDocCopy);
+ GenericDocument[] collectGiftCopy = genericDoc.getPropertyDocumentArray("collectGift");
+ List<Gift> collectGiftConv = null;
+ if (collectGiftCopy != null) {
+ DataClassFactory<Gift> factory = DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class);
+ collectGiftConv = new ArrayList<>(collectGiftCopy.length);
+ for (int i = 0; i < collectGiftCopy.length; i++) {
+ collectGiftConv.add(factory.fromGenericDocument(collectGiftCopy[i]));
+ }
}
long[] arrBoxLongCopy = genericDoc.getPropertyLongArray("arrBoxLong");
Long[] arrBoxLongConv = null;
@@ -559,7 +549,7 @@
}
boolean[] arrUnboxBooleanConv = genericDoc.getPropertyBooleanArray("arrUnboxBoolean");
byte[][] arrUnboxByteArrConv = genericDoc.getPropertyBytesArray("arrUnboxByteArr");
- byte[][] boxByteArrCopy = genericDoc.getPropertyBytesArray("boxByteArr");
+ byte[] boxByteArrCopy = genericDoc.getPropertyBytes("boxByteArr");
Byte[] boxByteArrConv = null;
if (boxByteArrCopy != null) {
boxByteArrConv = new Byte[boxByteArrCopy.length];
@@ -568,7 +558,6 @@
}
}
String[] arrStringConv = genericDoc.getPropertyStringArray("arrString");
- GenericDocument[] arrGenDocConv = genericDoc.getPropertyDocumentArray("arrGenDoc");
String[] stringCopy = genericDoc.getPropertyStringArray("string");
String stringConv = null;
if (stringCopy != null && stringCopy.length != 0) {
@@ -609,11 +598,6 @@
if (unboxByteArrCopy != null && unboxByteArrCopy.length != 0) {
unboxByteArrConv = unboxByteArrCopy[0];
}
- GenericDocument[] genDocumentCopy = genericDoc.getPropertyDocumentArray("genDocument");
- GenericDocument genDocumentConv = null;
- if (genDocumentCopy != null && genDocumentCopy.length != 0) {
- genDocumentConv = genDocumentCopy[0];
- }
Gift dataClass = new Gift();
dataClass.uri = uriConv;
dataClass.collectLong = collectLongConv;
@@ -623,7 +607,7 @@
dataClass.collectBoolean = collectBooleanConv;
dataClass.collectByteArr = collectByteArrConv;
dataClass.collectString = collectStringConv;
- dataClass.collectGenDoc = collectGenDocConv;
+ dataClass.collectGift = collectGiftConv;
dataClass.arrBoxLong = arrBoxLongConv;
dataClass.arrUnboxLong = arrUnboxLongConv;
dataClass.arrBoxInteger = arrBoxIntegerConv;
@@ -637,7 +621,6 @@
dataClass.arrUnboxByteArr = arrUnboxByteArrConv;
dataClass.boxByteArr = boxByteArrConv;
dataClass.arrString = arrStringConv;
- dataClass.arrGenDoc = arrGenDocConv;
dataClass.string = stringConv;
dataClass.boxLong = boxLongConv;
dataClass.unboxLong = unboxLongConv;
@@ -650,7 +633,6 @@
dataClass.boxBoolean = boxBooleanConv;
dataClass.unboxBoolean = unboxBooleanConv;
dataClass.unboxByteArr = unboxByteArrConv;
- dataClass.genDocument = genDocumentConv;
return dataClass;
}
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testTokenizerType.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testTokenizerType.JAVA
index 6644954..4610d01 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testTokenizerType.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testTokenizerType.JAVA
@@ -3,39 +3,38 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "Gift";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("tokNone")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("tokPlain")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("tokNone")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("tokPlain")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
String tokNoneCopy = dataClass.tokNone;
@@ -50,7 +49,7 @@
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
String[] tokNoneCopy = genericDoc.getPropertyStringArray("tokNone");
String tokNoneConv = null;
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_MultipleSetters.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_MultipleSetters.JAVA
index fdbae72..66c7ed7 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_MultipleSetters.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_MultipleSetters.JAVA
@@ -3,33 +3,32 @@
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.DataClassFactory;
import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
import java.lang.Override;
import java.lang.String;
public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
private static final String SCHEMA_TYPE = "Gift";
- private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .build())
- .build();
-
@Override
public String getSchemaType() {
return SCHEMA_TYPE;
}
@Override
- public AppSearchSchema getSchema() {
- return SCHEMA;
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_TYPE)
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
}
@Override
- public GenericDocument toGenericDocument(Gift dataClass) {
+ public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
GenericDocument.Builder<?> builder =
new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
builder.setProperty("price", dataClass.getPrice());
@@ -37,7 +36,7 @@
}
@Override
- public Gift fromGenericDocument(GenericDocument genericDoc) {
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
String uriConv = genericDoc.getUri();
int priceConv = genericDoc.getPropertyLong("price");
Gift dataClass = new Gift();
diff --git a/appsearch/export_to_framework.py b/appsearch/export_to_framework.py
new file mode 100755
index 0000000..c726855
--- /dev/null
+++ b/appsearch/export_to_framework.py
@@ -0,0 +1,213 @@
+#!/usr/bin/env python3
+# Copyright (C) 2020 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.
+
+# Exports AppSearch Androidx code to Framework
+#
+# NOTE: This will remove and replace all files in the
+# frameworks/base/apex/appsearch path.
+#
+# Example usage (from root dir of androidx workspace):
+# $ ./frameworks/support/appsearch/export_to_framework.py "$HOME/android/master"
+import os
+import re
+import sys
+
+
+JETPACK_API_ROOT = 'appsearch/src/main/java/androidx/appsearch'
+JETPACK_IMPL_ROOT = 'local-backend/src/main/java/androidx/appsearch'
+JETPACK_IMPL_TEST_ROOT = 'local-backend/src/androidTest/java/androidx/appsearch'
+FRAMEWORK_API_ROOT = 'framework/java/android/app/appsearch'
+FRAMEWORK_IMPL_ROOT = 'service/java/com/android/server/appsearch/external'
+FRAMEWORK_IMPL_TEST_ROOT = (
+ '../../services/tests/servicestests/src/'
+ 'com/android/server/appsearch/external')
+
+
+def _PruneDir(dest_dir, allow_list=None):
+ all_files = []
+ for walk_path, walk_folders, walk_files in os.walk(dest_dir):
+ for walk_filename in walk_files:
+ abs_path = os.path.join(walk_path, walk_filename)
+ all_files.append(abs_path)
+
+ for abs_path in all_files:
+ rel_path = os.path.relpath(abs_path, dest_dir)
+ if allow_list and rel_path in allow_list:
+ print('Prune: skip "%s"' % abs_path)
+ else:
+ print('Prune: remove "%s"' % abs_path)
+ os.remove(abs_path)
+
+
+def _TransformAndCopyFile(source_path, dest_path, transform_func=None):
+ print('Copy: "%s" -> "%s"' % (source_path, dest_path), file=sys.stderr)
+ with open(source_path, 'r') as fh:
+ contents = fh.read()
+ if transform_func:
+ contents = transform_func(contents)
+ os.makedirs(os.path.dirname(dest_path), exist_ok=True)
+ with open(dest_path, 'w') as fh:
+ fh.write(contents)
+
+
+def _TransformCommonCode(contents):
+ contents = (contents
+ .replace('androidx.appsearch.app', 'android.app.appsearch')
+ .replace('androidx.appsearch', 'android.app.appsearch')
+ .replace(
+ 'androidx.annotation.GuardedBy',
+ 'com.android.internal.annotations.GuardedBy')
+ .replace(
+ 'androidx.annotation.VisibleForTesting',
+ 'com.android.internal.annotations.VisibleForTesting')
+ .replace('androidx.collection.ArraySet', 'android.util.ArraySet')
+ .replace(
+ 'androidx.core.util.Preconditions',
+ 'com.android.internal.util.Preconditions')
+ .replace('import androidx.annotation.RestrictTo;', '')
+ .replace('@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)', '')
+ .replace('androidx', 'android')
+ )
+ return contents
+
+
+def _TransformApiCode(contents):
+ contents = (contents
+ .replace(
+ 'package androidx.appsearch.app;',
+ 'package android.app.appsearch;')
+ )
+ return _TransformCommonCode(contents)
+
+
+def _TransformImplCode(contents):
+ contents = (contents
+ .replace(
+ 'package androidx.appsearch',
+ 'package com.android.server.appsearch.external')
+ )
+ return _TransformCommonCode(contents)
+
+
+def _TransformImplTestCode(contents):
+ return (_TransformImplCode(contents)
+ .replace(
+ 'com.google.android.icing.proto.',
+ 'com.android.server.appsearch.proto.')
+ .replace('org.junit.Assert.assertThrows',
+ 'org.testng.Assert.expectThrows')
+ .replace('assertThrows(', 'expectThrows(')
+ )
+
+
+def _CopyAllApi(source_dir, dest_dir):
+ api_source_dir = os.path.join(source_dir, JETPACK_API_ROOT)
+ api_dest_dir = os.path.join(dest_dir, FRAMEWORK_API_ROOT)
+ # Prune existing files
+ _PruneDir(api_dest_dir, allow_list=[
+ 'AppSearchManager.java',
+ 'AppSearchManagerFrameworkInitializer.java',
+ 'IAppSearchManager.aidl',
+ ])
+
+ # Copy new files
+ for currentpath, folders, files in os.walk(api_source_dir):
+ dir_rel_to_root = os.path.relpath(currentpath, api_source_dir)
+ for filename in files:
+ # Copy all files, except those in the following block list
+ source_abs_path = os.path.join(currentpath, filename)
+ rel_to_api = os.path.relpath(source_abs_path, api_source_dir)
+ if rel_to_api in ('app/AppSearchManager.java'):
+ print('Skipping copy: "%s"' % rel_to_api)
+ continue
+
+ # Figure out what folder to place them into
+ if dir_rel_to_root == 'app':
+ # Files in the 'app' folder live in the root of the platform
+ # tree
+ dest_path = os.path.join(api_dest_dir, filename)
+ else:
+ dest_path = os.path.join(
+ api_dest_dir, dir_rel_to_root, filename)
+ _TransformAndCopyFile(source_abs_path, dest_path, _TransformApiCode)
+
+
+def _TransformAndCopyFolder(
+ source_dir, dest_dir, transform_func=None, block_list=None):
+ for currentpath, folders, files in os.walk(source_dir):
+ dir_rel_to_root = os.path.relpath(currentpath, source_dir)
+ for filename in files:
+ # Copy all files, except those in the block list
+ source_abs_path = os.path.join(currentpath, filename)
+ rel_to_source = os.path.relpath(source_abs_path, source_dir)
+ if block_list and rel_to_source in block_list:
+ print('Skipping copy: "%s"' % rel_to_source)
+ continue
+
+ dest_path = os.path.join(dest_dir, dir_rel_to_root, filename)
+ _TransformAndCopyFile(source_abs_path, dest_path, transform_func)
+
+
+def _CopyAllImpl(source_dir, dest_dir):
+ impl_source_dir = os.path.join(source_dir, JETPACK_IMPL_ROOT)
+ impl_test_source_dir = os.path.join(source_dir, JETPACK_IMPL_TEST_ROOT)
+ impl_dest_dir = os.path.join(dest_dir, FRAMEWORK_IMPL_ROOT)
+ impl_test_dest_dir = os.path.join(dest_dir, FRAMEWORK_IMPL_TEST_ROOT)
+
+ # Prune
+ _PruneDir(impl_dest_dir)
+ _PruneDir(impl_test_dest_dir)
+
+ # Copy impl classes
+ _TransformAndCopyFolder(
+ impl_source_dir, impl_dest_dir,
+ transform_func=_TransformImplCode,
+ block_list=[
+ 'localbackend/LocalBackend.java',
+ ])
+
+ # Copy servicestests
+ _TransformAndCopyFolder(
+ impl_test_source_dir, impl_test_dest_dir,
+ transform_func=_TransformImplTestCode,
+ block_list=[
+ 'localbackend/LocalBackendTest.java',
+ ])
+
+
+def _CopyMain(source_dir, dest_dir):
+ #_CopyAllApi(source_dir, dest_dir)
+ _CopyAllImpl(source_dir, dest_dir)
+
+
+if __name__ == '__main__':
+ if len(sys.argv) != 2:
+ print('Usage: %s <path/to/frameworks/base>' % sys.argv[0],
+ file=sys.stderr)
+ sys.exit(1)
+ source_dir = os.path.normpath(os.path.dirname(sys.argv[0]))
+ dest_dir = os.path.normpath(sys.argv[1])
+ if os.path.basename(dest_dir) == 'appsearch':
+ pass
+ elif os.path.basename(dest_dir) == 'base':
+ dest_dir = os.path.join(dest_dir, 'apex/appsearch')
+ else:
+ dest_dir = os.path.join(dest_dir, 'frameworks/base/apex/appsearch')
+ if not os.path.isdir(dest_dir):
+ print('Destination path "%s" does not exist or is not a directory' % (
+ dest_dir),
+ file=sys.stderr)
+ sys.exit(1)
+ _CopyMain(source_dir, dest_dir)
diff --git a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/app/GenericDocumentToProtoConverterTest.java b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/app/GenericDocumentToProtoConverterTest.java
new file mode 100644
index 0000000..23571fc
--- /dev/null
+++ b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/app/GenericDocumentToProtoConverterTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020 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 androidx.appsearch.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.protobuf.ByteString;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+public class GenericDocumentToProtoConverterTest {
+ private static final byte[] BYTE_ARRAY_1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
+ private static final byte[] BYTE_ARRAY_2 = new byte[]{(byte) 4, (byte) 5, (byte) 6, (byte) 7};
+ private static final GenericDocument DOCUMENT_PROPERTIES_1 = new GenericDocument
+ .Builder("sDocumentProperties1", "sDocumentPropertiesSchemaType1")
+ .setCreationTimestampMillis(12345L)
+ .build();
+ private static final GenericDocument DOCUMENT_PROPERTIES_2 = new GenericDocument
+ .Builder("sDocumentProperties2", "sDocumentPropertiesSchemaType2")
+ .setCreationTimestampMillis(6789L)
+ .build();
+
+ @Test
+ public void testDocumentProtoConvert() {
+ GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1")
+ .setCreationTimestampMillis(5L)
+ .setScore(1)
+ .setTtlMillis(1L)
+ .setNamespace("namespace")
+ .setProperty("longKey1", 1L)
+ .setProperty("doubleKey1", 1.0)
+ .setProperty("booleanKey1", true)
+ .setProperty("stringKey1", "test-value1")
+ .setProperty("byteKey1", BYTE_ARRAY_1, BYTE_ARRAY_2)
+ .setProperty("documentKey1", DOCUMENT_PROPERTIES_1)
+ .setProperty(GenericDocument.PROPERTIES_FIELD, DOCUMENT_PROPERTIES_2)
+ .build();
+
+ // Create the Document proto. Need to sort the property order by key.
+ DocumentProto.Builder documentProtoBuilder = DocumentProto.newBuilder()
+ .setUri("uri1")
+ .setSchema("schemaType1")
+ .setCreationTimestampMs(5L)
+ .setScore(1)
+ .setTtlMs(1L)
+ .setNamespace("namespace");
+ HashMap<String, PropertyProto.Builder> propertyProtoMap = new HashMap<>();
+ propertyProtoMap.put("longKey1",
+ PropertyProto.newBuilder().setName("longKey1").addInt64Values(1L));
+ propertyProtoMap.put("doubleKey1",
+ PropertyProto.newBuilder().setName("doubleKey1").addDoubleValues(1.0));
+ propertyProtoMap.put("booleanKey1",
+ PropertyProto.newBuilder().setName("booleanKey1").addBooleanValues(true));
+ propertyProtoMap.put("stringKey1",
+ PropertyProto.newBuilder().setName("stringKey1").addStringValues("test-value1"));
+ propertyProtoMap.put("byteKey1",
+ PropertyProto.newBuilder().setName("byteKey1")
+ .addBytesValues(ByteString.copyFrom(BYTE_ARRAY_1))
+ .addBytesValues(ByteString.copyFrom(BYTE_ARRAY_2)));
+ propertyProtoMap.put("documentKey1",
+ PropertyProto.newBuilder().setName("documentKey1")
+ .addDocumentValues(
+ GenericDocumentToProtoConverter.convert(DOCUMENT_PROPERTIES_1)));
+ propertyProtoMap.put(GenericDocument.PROPERTIES_FIELD,
+ PropertyProto.newBuilder().setName(GenericDocument.PROPERTIES_FIELD)
+ .addDocumentValues(
+ GenericDocumentToProtoConverter.convert(DOCUMENT_PROPERTIES_2)));
+ List<String> sortedKey = new ArrayList<>(propertyProtoMap.keySet());
+ Collections.sort(sortedKey);
+ for (String key : sortedKey) {
+ documentProtoBuilder.addProperties(propertyProtoMap.get(key));
+ }
+ DocumentProto documentProto = documentProtoBuilder.build();
+ assertThat(GenericDocumentToProtoConverter.convert(document))
+ .isEqualTo(documentProto);
+ assertThat(document).isEqualTo(GenericDocumentToProtoConverter.convert(documentProto));
+ }
+}
diff --git a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/app/SchemaToProtoConverterTest.java b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/app/SchemaToProtoConverterTest.java
new file mode 100644
index 0000000..0d0ec8c
--- /dev/null
+++ b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/app/SchemaToProtoConverterTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2020 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 androidx.appsearch.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.android.icing.proto.IndexingConfig;
+import com.google.android.icing.proto.PropertyConfigProto;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
+import com.google.android.icing.proto.TermMatchType;
+
+import org.junit.Test;
+
+public class SchemaToProtoConverterTest {
+ @Test
+ public void testGetProto_Email() {
+ AppSearchSchema emailSchema = new AppSearchSchema.Builder("Email")
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).addProperty(new AppSearchSchema.PropertyConfig.Builder("body")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+
+ SchemaTypeConfigProto expectedEmailProto = SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("Email")
+ .addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("subject")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setSchemaType("")
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setIndexingConfig(
+ com.google.android.icing.proto.IndexingConfig.newBuilder()
+ .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)
+ )
+ ).addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("body")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setSchemaType("")
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setIndexingConfig(
+ com.google.android.icing.proto.IndexingConfig.newBuilder()
+ .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)
+ )
+ ).build();
+
+ assertThat(SchemaToProtoConverter.convert(emailSchema)).isEqualTo(expectedEmailProto);
+ }
+
+ @Test
+ public void testGetProto_MusicRecording() {
+ AppSearchSchema musicRecordingSchema = new AppSearchSchema.Builder("MusicRecording")
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("artist")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).addProperty(new AppSearchSchema.PropertyConfig.Builder("pubDate")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+ .build()
+ ).build();
+
+ SchemaTypeConfigProto expectedMusicRecordingProto = SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("MusicRecording")
+ .addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("artist")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setSchemaType("")
+ .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
+ .setIndexingConfig(
+ com.google.android.icing.proto.IndexingConfig.newBuilder()
+ .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)
+ )
+ ).addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("pubDate")
+ .setDataType(PropertyConfigProto.DataType.Code.INT64)
+ .setSchemaType("")
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setIndexingConfig(
+ com.google.android.icing.proto.IndexingConfig.newBuilder()
+ .setTokenizerType(IndexingConfig.TokenizerType.Code.NONE)
+ .setTermMatchType(TermMatchType.Code.UNKNOWN)
+ )
+ ).build();
+
+ assertThat(SchemaToProtoConverter.convert(musicRecordingSchema))
+ .isEqualTo(expectedMusicRecordingProto);
+ }
+}
diff --git a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/AppSearchImplTest.java b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/AppSearchImplTest.java
index b400c41..046d19d 100644
--- a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/AppSearchImplTest.java
+++ b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/AppSearchImplTest.java
@@ -21,7 +21,6 @@
import static org.junit.Assert.assertThrows;
import androidx.appsearch.exceptions.AppSearchException;
-import androidx.test.core.app.ApplicationProvider;
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.GetOptimizeInfoResultProto;
@@ -38,18 +37,21 @@
import com.google.android.icing.proto.TermMatchType;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import java.util.Set;
public class AppSearchImplTest {
+ @Rule
+ public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
private AppSearchImpl mAppSearchImpl;
@Before
public void setUp() throws Exception {
- mAppSearchImpl = AppSearchImpl.getInstance();
- mAppSearchImpl.initialize(ApplicationProvider.getApplicationContext());
- mAppSearchImpl.reset();
+ mAppSearchImpl = new AppSearchImpl(mTemporaryFolder.newFolder());
+ mAppSearchImpl.initialize();
}
/**
@@ -226,7 +228,7 @@
}
@Test
- public void testQueryEmptyDatabase() throws AppSearchException, InterruptedException {
+ public void testQueryEmptyDatabase() throws Exception {
SearchResultProto searchResultProto = mAppSearchImpl.query("EmptyDatabase",
SearchSpecProto.getDefaultInstance(),
ResultSpecProto.getDefaultInstance(), ScoringSpecProto.getDefaultInstance());
@@ -235,8 +237,7 @@
}
@Test
- public void testRemoveEmptyDatabase_NoExceptionThrown()
- throws AppSearchException, InterruptedException {
+ public void testRemoveEmptyDatabase_NoExceptionThrown() throws Exception {
mAppSearchImpl.removeByType("EmptyDatabase", "FakeType");
mAppSearchImpl.removeByNamespace("EmptyDatabase", "FakeNamespace");
mAppSearchImpl.removeAll("EmptyDatabase");
diff --git a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/LocalBackendTest.java b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/LocalBackendTest.java
new file mode 100644
index 0000000..565470e
--- /dev/null
+++ b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/LocalBackendTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020 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 androidx.appsearch.localbackend;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Test;
+
+public class LocalBackendTest {
+ @Test
+ public void testSameInstance() {
+ LocalBackend b1 = LocalBackend.getInstance(ApplicationProvider.getApplicationContext())
+ .getResultValue();
+ LocalBackend b2 = LocalBackend.getInstance(ApplicationProvider.getApplicationContext())
+ .getResultValue();
+ assertThat(b1).isSameInstanceAs(b2);
+ }
+
+ @Test
+ public void testInitBlocking() {
+ LocalBackend backend = LocalBackend.getInstance(ApplicationProvider.getApplicationContext())
+ .getResultValue();
+ assertThat(backend.isInitialized()).isFalse();
+ Thread t = new Thread(() -> {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ backend.initialize().getResultValue();
+ });
+ t.setDaemon(true);
+ t.setName("startInit");
+ long startNs = System.nanoTime();
+ t.start();
+ backend.removeAll("db").getResultValue();
+ long endNs = System.nanoTime();
+ long elapsedMs = (endNs - startNs) / 1000 / 1000;
+ assertThat(elapsedMs).isAtLeast(1000);
+ assertThat(backend.isInitialized()).isTrue();
+ }
+}
diff --git a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/SnippetTest.java b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/SnippetTest.java
index 258be8a..715b8f6 100644
--- a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/SnippetTest.java
+++ b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/SnippetTest.java
@@ -83,7 +83,7 @@
for (SearchResultProto.ResultProto proto : searchResultProto.getResultsList()) {
SearchResults.Result result =
SearchResultToProtoConverter.convert(proto);
- MatchInfo match = result.getMatchInfo().get(0);
+ MatchInfo match = result.getMatches().get(0);
assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
assertThat(match.getFullText()).isEqualTo(propertyValueString);
assertThat(match.getExactMatch()).isEqualTo(exactMatch);
@@ -130,7 +130,7 @@
for (SearchResultProto.ResultProto proto : searchResultProto.getResultsList()) {
SearchResults.Result result =
SearchResultToProtoConverter.convert(proto);
- assertThat(result.getMatchInfo()).isEqualTo(null);
+ assertThat(result.getMatches()).isEqualTo(null);
}
}
@@ -193,7 +193,7 @@
SearchResults.Result result =
SearchResultToProtoConverter.convert(proto);
- MatchInfo match1 = result.getMatchInfo().get(0);
+ MatchInfo match1 = result.getMatches().get(0);
assertThat(match1.getPropertyPath()).isEqualTo("sender.name");
assertThat(match1.getFullText()).isEqualTo("Test Name Jr.");
assertThat(match1.getExactMatchPosition()).isEqualTo(
@@ -203,7 +203,7 @@
new MatchInfo.MatchRange(/*lower=*/0, /*upper=*/9));
assertThat(match1.getSnippet()).isEqualTo("Test Name");
- MatchInfo match2 = result.getMatchInfo().get(1);
+ MatchInfo match2 = result.getMatches().get(1);
assertThat(match2.getPropertyPath()).isEqualTo("sender.email");
assertThat(match2.getFullText()).isEqualTo("TestNameJr@gmail.com");
assertThat(match2.getExactMatchPosition()).isEqualTo(
diff --git a/appsearch/local-backend/src/main/java/androidx/appsearch/app/GenericDocumentToProtoConverter.java b/appsearch/local-backend/src/main/java/androidx/appsearch/app/GenericDocumentToProtoConverter.java
index 325f25a..155dde5 100644
--- a/appsearch/local-backend/src/main/java/androidx/appsearch/app/GenericDocumentToProtoConverter.java
+++ b/appsearch/local-backend/src/main/java/androidx/appsearch/app/GenericDocumentToProtoConverter.java
@@ -16,11 +16,18 @@
package androidx.appsearch.app;
+import android.os.Bundle;
+
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.core.util.Preconditions;
import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.protobuf.ByteString;
+
+import java.util.ArrayList;
+import java.util.Collections;
/**
* Translates a {@link GenericDocument} into a {@link DocumentProto}.
@@ -32,15 +39,112 @@
/** Converts a {@link GenericDocument} into a {@link DocumentProto}. */
@NonNull
+ @SuppressWarnings("unchecked")
public static DocumentProto convert(@NonNull GenericDocument document) {
Preconditions.checkNotNull(document);
- return document.getProto();
+ DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder();
+ mProtoBuilder.setUri(document.getUri())
+ .setSchema(document.getSchemaType())
+ .setNamespace(document.getNamespace())
+ .setScore(document.getScore())
+ .setTtlMs(document.getTtlMillis())
+ .setCreationTimestampMs(document.getCreationTimestampMillis());
+ ArrayList<String> keys = new ArrayList<>(document.mProperties.keySet());
+ Collections.sort(keys);
+ for (int i = 0; i < keys.size(); i++) {
+ String name = keys.get(i);
+ Object values = document.mProperties.get(name);
+ PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(name);
+ if (values instanceof boolean[]) {
+ for (boolean value : (boolean[]) values) {
+ propertyProto.addBooleanValues(value);
+ }
+ } else if (values instanceof long[]) {
+ for (long value : (long[]) values) {
+ propertyProto.addInt64Values(value);
+ }
+ } else if (values instanceof double[]) {
+ for (double value : (double[]) values) {
+ propertyProto.addDoubleValues(value);
+ }
+ } else if (values instanceof String[]) {
+ for (String value : (String[]) values) {
+ propertyProto.addStringValues(value);
+ }
+ } else if (values instanceof ArrayList) {
+ for (Bundle bundle : (ArrayList<Bundle>) values) {
+ propertyProto.addBytesValues(ByteString.copyFrom(
+ bundle.getByteArray(GenericDocument.BYTE_ARRAY_FIELD)));
+ }
+ } else if (values instanceof Bundle[]) {
+ for (Bundle bundle : (Bundle[]) values) {
+ propertyProto.addDocumentValues(convert(new GenericDocument(bundle)));
+ }
+ } else {
+ throw new IllegalStateException(
+ "Property \"" + name + "\" has unsupported value type \""
+ + values.getClass().getSimpleName() + "\"");
+ }
+ mProtoBuilder.addProperties(propertyProto);
+ }
+ return mProtoBuilder.build();
}
/** Converts a {@link DocumentProto} into a {@link GenericDocument}. */
@NonNull
public static GenericDocument convert(@NonNull DocumentProto proto) {
Preconditions.checkNotNull(proto);
- return new GenericDocument(proto);
+ GenericDocument.Builder documentBuilder =
+ new GenericDocument.Builder<>(proto.getUri(), proto.getSchema())
+ .setNamespace(proto.getNamespace())
+ .setScore(proto.getScore())
+ .setTtlMillis(proto.getTtlMs())
+ .setCreationTimestampMillis(proto.getCreationTimestampMs());
+
+ for (int i = 0; i < proto.getPropertiesCount(); i++) {
+ PropertyProto property = proto.getProperties(i);
+ String name = property.getName();
+ if (property.getBooleanValuesCount() > 0) {
+ boolean[] values = new boolean[property.getBooleanValuesCount()];
+ for (int j = 0; j < values.length; j++) {
+ values[j] = property.getBooleanValues(j);
+ }
+ documentBuilder.setProperty(name, values);
+ } else if (property.getInt64ValuesCount() > 0) {
+ long[] values = new long[property.getInt64ValuesCount()];
+ for (int j = 0; j < values.length; j++) {
+ values[j] = property.getInt64Values(j);
+ }
+ documentBuilder.setProperty(name, values);
+ } else if (property.getDoubleValuesCount() > 0) {
+ double[] values = new double[property.getDoubleValuesCount()];
+ for (int j = 0; j < values.length; j++) {
+ values[j] = property.getDoubleValues(j);
+ }
+ documentBuilder.setProperty(name, values);
+ } else if (property.getStringValuesCount() > 0) {
+ String[] values = new String[property.getStringValuesCount()];
+ for (int j = 0; j < values.length; j++) {
+ values[j] = property.getStringValues(j);
+ }
+ documentBuilder.setProperty(name, values);
+ } else if (property.getBytesValuesCount() > 0) {
+ byte[][] values = new byte[property.getBytesValuesCount()][];
+ for (int j = 0; j < values.length; j++) {
+ values[j] = property.getBytesValues(j).toByteArray();
+ }
+ documentBuilder.setProperty(name, values);
+ } else if (property.getDocumentValuesCount() > 0) {
+ GenericDocument[] values =
+ new GenericDocument[property.getDocumentValuesCount()];
+ for (int j = 0; j < values.length; j++) {
+ values[j] = new GenericDocument(convert(property.getDocumentValues(j)));
+ }
+ documentBuilder.setProperty(name, values);
+ } else {
+ throw new IllegalStateException("Unknown type of value: " + name);
+ }
+ }
+ return documentBuilder.build();
}
}
diff --git a/appsearch/local-backend/src/main/java/androidx/appsearch/app/SearchSpecToProtoConverter.java b/appsearch/local-backend/src/main/java/androidx/appsearch/app/SearchSpecToProtoConverter.java
index 00cb905d..1250f37 100644
--- a/appsearch/local-backend/src/main/java/androidx/appsearch/app/SearchSpecToProtoConverter.java
+++ b/appsearch/local-backend/src/main/java/androidx/appsearch/app/SearchSpecToProtoConverter.java
@@ -71,9 +71,9 @@
.setNumPerPage(bundle.getInt(
SearchSpec.NUM_PER_PAGE_FIELD, SearchSpec.DEFAULT_NUM_PER_PAGE))
.setSnippetSpec(ResultSpecProto.SnippetSpecProto.newBuilder()
- .setNumToSnippet(bundle.getInt(SearchSpec.NUM_TO_SNIPPET_FIELD))
+ .setNumToSnippet(bundle.getInt(SearchSpec.SNIPPET_COUNT_FIELD))
.setNumMatchesPerProperty(
- bundle.getInt(SearchSpec.NUM_MATCHED_PER_PROPERTY_FIELD))
+ bundle.getInt(SearchSpec.SNIPPET_COUNT_PER_PROPERTY_FIELD))
.setMaxWindowBytes(bundle.getInt(SearchSpec.MAX_SNIPPET_FIELD)))
.build();
diff --git a/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/AppSearchImpl.java b/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/AppSearchImpl.java
index ddd3b91..30acc31 100644
--- a/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/AppSearchImpl.java
+++ b/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/AppSearchImpl.java
@@ -16,14 +16,15 @@
package androidx.appsearch.localbackend;
-import android.content.Context;
import android.util.Log;
+import androidx.annotation.AnyThread;
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
import androidx.appsearch.app.AppSearchResult;
import androidx.appsearch.exceptions.AppSearchException;
@@ -52,66 +53,67 @@
import com.google.android.icing.proto.SetSchemaResultProto;
import com.google.android.icing.proto.StatusProto;
-import java.io.IOException;
+import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
-
/**
* Manages interaction with the native IcingSearchEngine and other components to implement AppSearch
* functionality.
*
- * <p>Callers should use {@link #getInstance} to retrieve the singleton instance and call
- * {@link #initialize} before using the class.
+ * <p>Callers should call {@link #initialize} before using the AppSearchImpl instance. Never create
+ * two instances using the same folder.
*
- * <p>The singleton instance of {@link AppSearchImpl} supports all instances of
- * {@link androidx.appsearch.app.AppSearchManager} with different database name. All logically
- * isolated schemas and documents will be physically saved together in IcingSearchEngine.
- * The way to isolated those schemas and documents for different database:
+ * <p>A single instance of {@link AppSearchImpl} can support all databases. Schemas and documents
+ * are physically saved together in {@link IcingSearchEngine}, but logically isolated:
* <ul>
* <li>Rewrite SchemaType in SchemaProto by adding database name prefix and save into
- * SchemaTypes set in {@link #setSchema(String, SchemaProto, boolean)}.
+ * SchemaTypes set in {@link #setSchema}.
* <li>Rewrite namespace and SchemaType in DocumentProto by adding database name prefix and
- * save to namespaces set in {@link #putDocument(String, DocumentProto)}.
- * <li>Remove database name prefix when retrieve documents in
- * {@link #getDocument(String, String, String)}, and
- * {@link #query(String, SearchSpecProto, ResultSpecProto, ScoringSpecProto)}.
+ * save to namespaces set in {@link #putDocument}.
+ * <li>Remove database name prefix when retrieve documents in {@link #getDocument} and
+ * {@link #query}.
* <li>Rewrite filters in {@link SearchSpecProto} to have all namespaces and schema types of
- * the queried database when user using empty filters in
- * {@link #query(String, SearchSpecProto, ResultSpecProto, ScoringSpecProto)}.
+ * the queried database when user using empty filters in {@link #query}.
* </ul>
*
* <p>Methods in this class belong to two groups, the query group and the mutate group.
* <ul>
- * <li>All methods are going to modify global parameters and data in Icing should be executed
- * under WRITE lock to keep thread safety.
- * <li>All methods are going to access global parameters or query data from Icing
- * should be executed under READ lock to improve query performance.
+ * <li>All methods are going to modify global parameters and data in Icing are executed under
+ * WRITE lock to keep thread safety.
+ * <li>All methods are going to access global parameters or query data from Icing are executed
+ * under READ lock to improve query performance.
* </ul>
+ *
+ * <p>This class is thread safe.
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@WorkerThread
public final class AppSearchImpl {
- private static volatile AppSearchImpl sInstance;
private static final String TAG = "AppSearchImpl";
- private static final String ICING_DIR = "/icing";
+
@VisibleForTesting
static final int OPTIMIZE_THRESHOLD_DOC_COUNT = 1000;
@VisibleForTesting
static final int OPTIMIZE_THRESHOLD_BYTES = 1_000_000; // 1MB
@VisibleForTesting
static final int CHECK_OPTIMIZE_INTERVAL = 100;
- private final ReentrantReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();
+
+ private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();
private final CountDownLatch mInitCompleteLatch = new CountDownLatch(1);
+ private final File mIcingDir;
+ private IcingSearchEngine mIcingSearchEngine;
+
// The map contains schemaTypes and namespaces for all database. All values in the map have
// been already added database name prefix.
- private final HashMap<String, Set<String>> mSchemaMap = new HashMap<>();
- private final HashMap<String, Set<String>> mNamespaceMap = new HashMap<>();
- private IcingSearchEngine mIcingSearchEngine;
- private volatile boolean mInitialized = false;
+ private final Map<String, Set<String>> mSchemaMap = new HashMap<>();
+ private final Map<String, Set<String>> mNamespaceMap = new HashMap<>();
/**
* The counter to check when to call {@link #checkForOptimize(boolean)}. The interval is
@@ -119,20 +121,10 @@
*/
private int mOptimizeIntervalCount = 0;
- /** Gets the singleton instance of {@link AppSearchImpl} */
- @NonNull
- public static AppSearchImpl getInstance() {
- if (sInstance == null) {
- synchronized (AppSearchImpl.class) {
- if (sInstance == null) {
- sInstance = new AppSearchImpl();
- }
- }
- }
- return sInstance;
- }
-
- private AppSearchImpl() {
+ /** Creates an instance of {@link AppSearchImpl} which writes data to the given folder. */
+ @AnyThread
+ public AppSearchImpl(@NonNull File icingDir) {
+ mIcingDir = icingDir;
}
/**
@@ -140,10 +132,9 @@
*
* <p>This method belongs to mutate group.
*
- * @throws IOException on error opening directory.
* @throws AppSearchException on IcingSearchEngine error.
*/
- public void initialize(@NonNull Context context) throws IOException, AppSearchException {
+ public void initialize() throws AppSearchException {
if (isInitialized()) {
return;
}
@@ -155,9 +146,8 @@
if (isInitialized()) {
return;
}
-
- IcingSearchEngineOptions options = IcingSearchEngineOptions.newBuilder().setBaseDir(
- context.getFilesDir().getCanonicalPath() + ICING_DIR).build();
+ IcingSearchEngineOptions options = IcingSearchEngineOptions.newBuilder()
+ .setBaseDir(mIcingDir.getAbsolutePath()).build();
mIcingSearchEngine = new IcingSearchEngine(options);
InitializeResultProto initializeResultProto = mIcingSearchEngine.initialize();
@@ -180,7 +170,6 @@
for (String qualifiedNamespace : getAllNamespacesResultProto.getNamespacesList()) {
addToMap(mNamespaceMap, getDatabaseName(qualifiedNamespace), qualifiedNamespace);
}
- mInitialized = true;
mInitCompleteLatch.countDown();
if (!isReset) {
checkForOptimize(/* force= */ true);
@@ -191,8 +180,9 @@
}
/** Checks if the internal state of {@link AppSearchImpl} has been initialized. */
+ @AnyThread
public boolean isInitialized() {
- return mInitialized;
+ return mInitCompleteLatch.getCount() == 0;
}
/**
@@ -209,7 +199,7 @@
*/
public void setSchema(@NonNull String databaseName, @NonNull SchemaProto origSchema,
boolean forceOverride) throws AppSearchException, InterruptedException {
- checkInitialized();
+ awaitInitialized();
SchemaProto schemaProto = getSchemaProto();
@@ -251,7 +241,7 @@
*/
public void putDocument(@NonNull String databaseName, @NonNull DocumentProto document)
throws AppSearchException, InterruptedException {
- checkInitialized();
+ awaitInitialized();
DocumentProto.Builder documentBuilder = document.toBuilder();
rewriteDocumentTypes(getDatabasePrefix(databaseName), documentBuilder, /*add=*/ true);
@@ -285,7 +275,7 @@
@Nullable
public DocumentProto getDocument(@NonNull String databaseName, @NonNull String namespace,
@NonNull String uri) throws AppSearchException, InterruptedException {
- checkInitialized();
+ awaitInitialized();
GetResultProto getResultProto;
mReadWriteLock.readLock().lock();
try {
@@ -321,7 +311,7 @@
@NonNull SearchSpecProto searchSpec,
@NonNull ResultSpecProto resultSpec,
@NonNull ScoringSpecProto scoringSpec) throws AppSearchException, InterruptedException {
- checkInitialized();
+ awaitInitialized();
SearchSpecProto.Builder searchSpecBuilder = searchSpec.toBuilder();
SearchResultProto searchResultProto;
@@ -362,7 +352,7 @@
@NonNull
public SearchResultProto getNextPage(@NonNull String databaseName, long nextPageToken)
throws AppSearchException, InterruptedException {
- checkInitialized();
+ awaitInitialized();
SearchResultProto searchResultProto = mIcingSearchEngine.getNextPage(nextPageToken);
checkSuccess(searchResultProto.getStatus());
@@ -377,10 +367,8 @@
* @param nextPageToken The token of pre-loaded results of previously executed query to be
* Invalidated.
*/
- public void invalidateNextPageToken(long nextPageToken)
- throws AppSearchException, InterruptedException {
- checkInitialized();
-
+ public void invalidateNextPageToken(long nextPageToken) throws InterruptedException {
+ awaitInitialized();
mIcingSearchEngine.invalidateNextPageToken(nextPageToken);
}
@@ -397,7 +385,7 @@
*/
public void remove(@NonNull String databaseName, @NonNull String namespace,
@NonNull String uri) throws AppSearchException, InterruptedException {
- checkInitialized();
+ awaitInitialized();
String qualifiedNamespace = getDatabasePrefix(databaseName) + namespace;
DeleteResultProto deleteResultProto;
@@ -423,7 +411,7 @@
*/
public void removeByType(@NonNull String databaseName, @NonNull String schemaType)
throws AppSearchException, InterruptedException {
- checkInitialized();
+ awaitInitialized();
String qualifiedType = getDatabasePrefix(databaseName) + schemaType;
DeleteBySchemaTypeResultProto deleteBySchemaTypeResultProto;
@@ -453,7 +441,7 @@
*/
public void removeByNamespace(@NonNull String databaseName, @NonNull String namespace)
throws AppSearchException, InterruptedException {
- checkInitialized();
+ awaitInitialized();
String qualifiedNamespace = getDatabasePrefix(databaseName) + namespace;
DeleteByNamespaceResultProto deleteByNamespaceResultProto;
@@ -485,7 +473,7 @@
*/
public void removeAll(@NonNull String databaseName)
throws AppSearchException, InterruptedException {
- checkInitialized();
+ awaitInitialized();
mReadWriteLock.writeLock().lock();
try {
Set<String> existingNamespaces = mNamespaceMap.get(databaseName);
@@ -518,8 +506,6 @@
*/
@VisibleForTesting
public void reset() throws AppSearchException {
- // Clear data from IcingSearchEngine.
-
ResetResultProto resetResultProto;
mReadWriteLock.writeLock().lock();
try {
@@ -662,8 +648,6 @@
* safety.
* @return false if the current database is brand new and contains nothing. We should just
* return an empty query result to user.
- * @throws AppSearchException if there is no schema type or document has been saved in this
- * database.
*/
@VisibleForTesting
@GuardedBy("mReadWriteLock")
@@ -739,8 +723,7 @@
}
@GuardedBy("mReadWriteLock")
- private void addToMap(HashMap<String, Set<String>> map, String databaseName,
- String prefixedValue) {
+ private void addToMap(Map<String, Set<String>> map, String databaseName, String prefixedValue) {
Set<String> values = map.get(databaseName);
if (values == null) {
values = new HashSet<>();
@@ -750,17 +733,12 @@
}
/**
- * Ensure the instance is intialized.
+ * Waits for the instance to become initialized.
*
- * @throws AppSearchException if not.
- * @throws InterruptedException if the current thread was interrupted during execution.
+ * @throws InterruptedException if the current thread was interrupted during waiting.
*/
- private void checkInitialized() throws AppSearchException, InterruptedException {
+ private void awaitInitialized() throws InterruptedException {
mInitCompleteLatch.await();
- if (!isInitialized()) {
- throw new AppSearchException(AppSearchResult.RESULT_INTERNAL_ERROR,
- "Accessing an uninitialized AppSearchImpl");
- }
}
/**
diff --git a/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/LocalBackend.java b/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/LocalBackend.java
index 426adb2..ef1329d 100644
--- a/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/LocalBackend.java
+++ b/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/LocalBackend.java
@@ -17,9 +17,11 @@
package androidx.appsearch.localbackend;
import static androidx.appsearch.app.AppSearchResult.newFailedResult;
+import static androidx.appsearch.app.AppSearchResult.newSuccessfulResult;
import android.content.Context;
+import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
@@ -44,6 +46,7 @@
import com.google.android.icing.proto.SearchResultProto;
import com.google.android.icing.proto.SearchSpecProto;
+import java.io.File;
import java.io.IOException;
import java.util.List;
@@ -54,35 +57,38 @@
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class LocalBackend implements AppSearchBackend {
- private final Context mContext;
+ private static final String ICING_DIR = "icing";
+
+ private static volatile AppSearchResult<LocalBackend> sInstance;
+
final AppSearchImpl mAppSearchImpl;
- /** Builder class for {@link LocalBackend} objects. */
- public static final class Builder {
- private final Context mContext;
- private boolean mBuilt = false;
-
- /** Constructs a new Builder with default settings using the provided {@code context}. */
- public Builder(@NonNull Context context) {
- Preconditions.checkNotNull(context);
- mContext = context;
+ /**
+ * Returns an instance of {@link LocalBackend}.
+ *
+ * <p>If no instance exists, one will be created using the provided {@code context}, but not
+ * initialized.
+ *
+ * <p>You must call {@link #initialize} before using it.
+ */
+ @AnyThread
+ @NonNull
+ public static AppSearchResult<LocalBackend> getInstance(@NonNull Context context) {
+ Preconditions.checkNotNull(context);
+ if (sInstance == null) {
+ synchronized (LocalBackend.class) {
+ if (sInstance == null) {
+ File icingDir = new File(context.getFilesDir(), ICING_DIR);
+ sInstance = newSuccessfulResult(new LocalBackend(icingDir));
+ }
+ }
}
-
- /**
- * Connects to the AppSearch database per this builder's configuration, and asynchronously
- * returns the initialized instance.
- */
- @NonNull
- public AppSearchResult<LocalBackend> build() {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- mBuilt = true;
- return AppSearchResult.newSuccessfulResult(new LocalBackend(mContext));
- }
+ return sInstance;
}
- LocalBackend(@NonNull Context context) {
- mContext = context;
- mAppSearchImpl = AppSearchImpl.getInstance();
+ @AnyThread
+ private LocalBackend(@NonNull File icingDir) {
+ mAppSearchImpl = new AppSearchImpl(icingDir);
}
@Override
@@ -95,7 +101,7 @@
public AppSearchResult<Void> initialize() {
if (!mAppSearchImpl.isInitialized()) {
try {
- mAppSearchImpl.initialize(mContext);
+ mAppSearchImpl.initialize();
} catch (Throwable t) {
return throwableToFailedResult(t);
}
@@ -347,7 +353,7 @@
public void close() throws IOException {
try {
mAppSearchImpl.invalidateNextPageToken(mNextPageToken);
- } catch (AppSearchException | InterruptedException e) {
+ } catch (InterruptedException e) {
throw new IOException(e);
}
}
diff --git a/autofill/autofill/api/1.1.0-beta01.txt b/autofill/autofill/api/1.1.0-beta01.txt
new file mode 100644
index 0000000..98cfd23
--- /dev/null
+++ b/autofill/autofill/api/1.1.0-beta01.txt
@@ -0,0 +1,180 @@
+// Signature format: 3.0
+package androidx.autofill {
+
+ public final class HintConstants {
+ method public static String generateSmsOtpHintForCharacterPosition(int);
+ field public static final String AUTOFILL_HINT_BIRTH_DATE_DAY = "birthDateDay";
+ field public static final String AUTOFILL_HINT_BIRTH_DATE_FULL = "birthDateFull";
+ field public static final String AUTOFILL_HINT_BIRTH_DATE_MONTH = "birthDateMonth";
+ field public static final String AUTOFILL_HINT_BIRTH_DATE_YEAR = "birthDateYear";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = "creditCardExpirationYear";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode";
+ field public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress";
+ field public static final String AUTOFILL_HINT_GENDER = "gender";
+ field @Deprecated public static final String AUTOFILL_HINT_NAME = "name";
+ field public static final String AUTOFILL_HINT_NEW_PASSWORD = "newPassword";
+ field public static final String AUTOFILL_HINT_NEW_USERNAME = "newUsername";
+ field public static final String AUTOFILL_HINT_PASSWORD = "password";
+ field public static final String AUTOFILL_HINT_PERSON_NAME = "personName";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_FAMILY = "personFamilyName";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_GIVEN = "personGivenName";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_MIDDLE = "personMiddleName";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_MIDDLE_INITIAL = "personMiddleInitial";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_PREFIX = "personNamePrefix";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_SUFFIX = "personNameSuffix";
+ field @Deprecated public static final String AUTOFILL_HINT_PHONE = "phone";
+ field public static final String AUTOFILL_HINT_PHONE_COUNTRY_CODE = "phoneCountryCode";
+ field public static final String AUTOFILL_HINT_PHONE_NATIONAL = "phoneNational";
+ field public static final String AUTOFILL_HINT_PHONE_NUMBER = "phoneNumber";
+ field public static final String AUTOFILL_HINT_PHONE_NUMBER_DEVICE = "phoneNumberDevice";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_COUNTRY = "addressCountry";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_ADDRESS = "extendedAddress";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_POSTAL_CODE = "extendedPostalCode";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_LOCALITY = "addressLocality";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_REGION = "addressRegion";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_STREET_ADDRESS = "streetAddress";
+ field public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode";
+ field public static final String AUTOFILL_HINT_SMS_OTP = "smsOTPCode";
+ field public static final String AUTOFILL_HINT_USERNAME = "username";
+ }
+
+}
+
+package androidx.autofill.inline {
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class Renderer {
+ method public static android.app.PendingIntent? getAttributionIntent(android.app.slice.Slice);
+ method public static android.os.Bundle getSupportedInlineUiVersionsAsBundle();
+ method public static android.view.View? render(android.content.Context, android.app.slice.Slice, android.os.Bundle);
+ }
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class SuggestionHintConstants {
+ field public static final String SUGGESTION_HINT_CLIPBOARD_CONTENT = "clipboardContent";
+ field public static final String SUGGESTION_HINT_SMART_REPLY = "smartReply";
+ }
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class UiVersions {
+ method public static java.util.List<java.lang.String!> getVersions(android.os.Bundle);
+ method public static androidx.autofill.inline.UiVersions.StylesBuilder newStylesBuilder();
+ field public static final String INLINE_UI_VERSION_1 = "androidx.autofill.inline.ui.version:v1";
+ }
+
+ public static interface UiVersions.Content {
+ method public android.app.slice.Slice getSlice();
+ }
+
+ public static interface UiVersions.Style {
+ }
+
+ public static final class UiVersions.StylesBuilder {
+ method public androidx.autofill.inline.UiVersions.StylesBuilder addStyle(androidx.autofill.inline.UiVersions.Style);
+ method public android.os.Bundle build();
+ }
+
+}
+
+package androidx.autofill.inline.common {
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class ImageViewStyle extends androidx.autofill.inline.common.ViewStyle {
+ }
+
+ public static final class ImageViewStyle.Builder {
+ ctor public ImageViewStyle.Builder();
+ method public androidx.autofill.inline.common.ImageViewStyle build();
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setBackgroundColor(int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setLayoutMargin(int, int, int, int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setMaxHeight(int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setMaxWidth(int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setPadding(int, int, int, int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setScaleType(android.widget.ImageView.ScaleType);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setTintList(android.content.res.ColorStateList);
+ }
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class TextViewStyle extends androidx.autofill.inline.common.ViewStyle {
+ }
+
+ public static final class TextViewStyle.Builder {
+ ctor public TextViewStyle.Builder();
+ method public androidx.autofill.inline.common.TextViewStyle build();
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setBackgroundColor(int);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setLayoutMargin(int, int, int, int);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setPadding(int, int, int, int);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setTextColor(@ColorInt int);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setTextSize(float);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setTextSize(int, float);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setTypeface(String, int);
+ }
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public class ViewStyle {
+ }
+
+ public static final class ViewStyle.Builder {
+ ctor public ViewStyle.Builder();
+ method public androidx.autofill.inline.common.ViewStyle build();
+ method public androidx.autofill.inline.common.ViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.common.ViewStyle.Builder setBackgroundColor(int);
+ method public androidx.autofill.inline.common.ViewStyle.Builder setLayoutMargin(int, int, int, int);
+ method public androidx.autofill.inline.common.ViewStyle.Builder setPadding(int, int, int, int);
+ }
+
+}
+
+package androidx.autofill.inline.v1 {
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class InlineSuggestionUi {
+ method public static androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder newContentBuilder(android.app.PendingIntent);
+ method public static androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder newStyleBuilder();
+ }
+
+ public static final class InlineSuggestionUi.Content implements androidx.autofill.inline.UiVersions.Content {
+ method public android.app.PendingIntent? getAttributionIntent();
+ method public CharSequence? getContentDescription();
+ method public android.graphics.drawable.Icon? getEndIcon();
+ method public final android.app.slice.Slice getSlice();
+ method public android.graphics.drawable.Icon? getStartIcon();
+ method public CharSequence? getSubtitle();
+ method public CharSequence? getTitle();
+ }
+
+ public static final class InlineSuggestionUi.Content.Builder {
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content build();
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setContentDescription(CharSequence);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setEndIcon(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setHints(java.util.List<java.lang.String!>);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setStartIcon(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setSubtitle(CharSequence);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setTitle(CharSequence);
+ }
+
+ public static final class InlineSuggestionUi.Style implements androidx.autofill.inline.UiVersions.Style {
+ method public androidx.autofill.inline.common.ViewStyle? getChipStyle();
+ method public androidx.autofill.inline.common.ImageViewStyle? getEndIconStyle();
+ method public int getLayoutDirection();
+ method public androidx.autofill.inline.common.ImageViewStyle? getSingleIconChipIconStyle();
+ method public androidx.autofill.inline.common.ViewStyle? getSingleIconChipStyle();
+ method public androidx.autofill.inline.common.ImageViewStyle? getStartIconStyle();
+ method public androidx.autofill.inline.common.TextViewStyle? getSubtitleStyle();
+ method public androidx.autofill.inline.common.TextViewStyle? getTitleStyle();
+ }
+
+ public static final class InlineSuggestionUi.Style.Builder {
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style build();
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setChipStyle(androidx.autofill.inline.common.ViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setEndIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setLayoutDirection(int);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSingleIconChipIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSingleIconChipStyle(androidx.autofill.inline.common.ViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setStartIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSubtitleStyle(androidx.autofill.inline.common.TextViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setTitleStyle(androidx.autofill.inline.common.TextViewStyle);
+ }
+
+}
+
diff --git a/autofill/autofill/api/public_plus_experimental_1.1.0-beta01.txt b/autofill/autofill/api/public_plus_experimental_1.1.0-beta01.txt
new file mode 100644
index 0000000..98cfd23
--- /dev/null
+++ b/autofill/autofill/api/public_plus_experimental_1.1.0-beta01.txt
@@ -0,0 +1,180 @@
+// Signature format: 3.0
+package androidx.autofill {
+
+ public final class HintConstants {
+ method public static String generateSmsOtpHintForCharacterPosition(int);
+ field public static final String AUTOFILL_HINT_BIRTH_DATE_DAY = "birthDateDay";
+ field public static final String AUTOFILL_HINT_BIRTH_DATE_FULL = "birthDateFull";
+ field public static final String AUTOFILL_HINT_BIRTH_DATE_MONTH = "birthDateMonth";
+ field public static final String AUTOFILL_HINT_BIRTH_DATE_YEAR = "birthDateYear";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = "creditCardExpirationYear";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode";
+ field public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress";
+ field public static final String AUTOFILL_HINT_GENDER = "gender";
+ field @Deprecated public static final String AUTOFILL_HINT_NAME = "name";
+ field public static final String AUTOFILL_HINT_NEW_PASSWORD = "newPassword";
+ field public static final String AUTOFILL_HINT_NEW_USERNAME = "newUsername";
+ field public static final String AUTOFILL_HINT_PASSWORD = "password";
+ field public static final String AUTOFILL_HINT_PERSON_NAME = "personName";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_FAMILY = "personFamilyName";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_GIVEN = "personGivenName";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_MIDDLE = "personMiddleName";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_MIDDLE_INITIAL = "personMiddleInitial";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_PREFIX = "personNamePrefix";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_SUFFIX = "personNameSuffix";
+ field @Deprecated public static final String AUTOFILL_HINT_PHONE = "phone";
+ field public static final String AUTOFILL_HINT_PHONE_COUNTRY_CODE = "phoneCountryCode";
+ field public static final String AUTOFILL_HINT_PHONE_NATIONAL = "phoneNational";
+ field public static final String AUTOFILL_HINT_PHONE_NUMBER = "phoneNumber";
+ field public static final String AUTOFILL_HINT_PHONE_NUMBER_DEVICE = "phoneNumberDevice";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_COUNTRY = "addressCountry";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_ADDRESS = "extendedAddress";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_POSTAL_CODE = "extendedPostalCode";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_LOCALITY = "addressLocality";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_REGION = "addressRegion";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_STREET_ADDRESS = "streetAddress";
+ field public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode";
+ field public static final String AUTOFILL_HINT_SMS_OTP = "smsOTPCode";
+ field public static final String AUTOFILL_HINT_USERNAME = "username";
+ }
+
+}
+
+package androidx.autofill.inline {
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class Renderer {
+ method public static android.app.PendingIntent? getAttributionIntent(android.app.slice.Slice);
+ method public static android.os.Bundle getSupportedInlineUiVersionsAsBundle();
+ method public static android.view.View? render(android.content.Context, android.app.slice.Slice, android.os.Bundle);
+ }
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class SuggestionHintConstants {
+ field public static final String SUGGESTION_HINT_CLIPBOARD_CONTENT = "clipboardContent";
+ field public static final String SUGGESTION_HINT_SMART_REPLY = "smartReply";
+ }
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class UiVersions {
+ method public static java.util.List<java.lang.String!> getVersions(android.os.Bundle);
+ method public static androidx.autofill.inline.UiVersions.StylesBuilder newStylesBuilder();
+ field public static final String INLINE_UI_VERSION_1 = "androidx.autofill.inline.ui.version:v1";
+ }
+
+ public static interface UiVersions.Content {
+ method public android.app.slice.Slice getSlice();
+ }
+
+ public static interface UiVersions.Style {
+ }
+
+ public static final class UiVersions.StylesBuilder {
+ method public androidx.autofill.inline.UiVersions.StylesBuilder addStyle(androidx.autofill.inline.UiVersions.Style);
+ method public android.os.Bundle build();
+ }
+
+}
+
+package androidx.autofill.inline.common {
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class ImageViewStyle extends androidx.autofill.inline.common.ViewStyle {
+ }
+
+ public static final class ImageViewStyle.Builder {
+ ctor public ImageViewStyle.Builder();
+ method public androidx.autofill.inline.common.ImageViewStyle build();
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setBackgroundColor(int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setLayoutMargin(int, int, int, int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setMaxHeight(int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setMaxWidth(int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setPadding(int, int, int, int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setScaleType(android.widget.ImageView.ScaleType);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setTintList(android.content.res.ColorStateList);
+ }
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class TextViewStyle extends androidx.autofill.inline.common.ViewStyle {
+ }
+
+ public static final class TextViewStyle.Builder {
+ ctor public TextViewStyle.Builder();
+ method public androidx.autofill.inline.common.TextViewStyle build();
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setBackgroundColor(int);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setLayoutMargin(int, int, int, int);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setPadding(int, int, int, int);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setTextColor(@ColorInt int);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setTextSize(float);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setTextSize(int, float);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setTypeface(String, int);
+ }
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public class ViewStyle {
+ }
+
+ public static final class ViewStyle.Builder {
+ ctor public ViewStyle.Builder();
+ method public androidx.autofill.inline.common.ViewStyle build();
+ method public androidx.autofill.inline.common.ViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.common.ViewStyle.Builder setBackgroundColor(int);
+ method public androidx.autofill.inline.common.ViewStyle.Builder setLayoutMargin(int, int, int, int);
+ method public androidx.autofill.inline.common.ViewStyle.Builder setPadding(int, int, int, int);
+ }
+
+}
+
+package androidx.autofill.inline.v1 {
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class InlineSuggestionUi {
+ method public static androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder newContentBuilder(android.app.PendingIntent);
+ method public static androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder newStyleBuilder();
+ }
+
+ public static final class InlineSuggestionUi.Content implements androidx.autofill.inline.UiVersions.Content {
+ method public android.app.PendingIntent? getAttributionIntent();
+ method public CharSequence? getContentDescription();
+ method public android.graphics.drawable.Icon? getEndIcon();
+ method public final android.app.slice.Slice getSlice();
+ method public android.graphics.drawable.Icon? getStartIcon();
+ method public CharSequence? getSubtitle();
+ method public CharSequence? getTitle();
+ }
+
+ public static final class InlineSuggestionUi.Content.Builder {
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content build();
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setContentDescription(CharSequence);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setEndIcon(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setHints(java.util.List<java.lang.String!>);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setStartIcon(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setSubtitle(CharSequence);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setTitle(CharSequence);
+ }
+
+ public static final class InlineSuggestionUi.Style implements androidx.autofill.inline.UiVersions.Style {
+ method public androidx.autofill.inline.common.ViewStyle? getChipStyle();
+ method public androidx.autofill.inline.common.ImageViewStyle? getEndIconStyle();
+ method public int getLayoutDirection();
+ method public androidx.autofill.inline.common.ImageViewStyle? getSingleIconChipIconStyle();
+ method public androidx.autofill.inline.common.ViewStyle? getSingleIconChipStyle();
+ method public androidx.autofill.inline.common.ImageViewStyle? getStartIconStyle();
+ method public androidx.autofill.inline.common.TextViewStyle? getSubtitleStyle();
+ method public androidx.autofill.inline.common.TextViewStyle? getTitleStyle();
+ }
+
+ public static final class InlineSuggestionUi.Style.Builder {
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style build();
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setChipStyle(androidx.autofill.inline.common.ViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setEndIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setLayoutDirection(int);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSingleIconChipIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSingleIconChipStyle(androidx.autofill.inline.common.ViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setStartIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSubtitleStyle(androidx.autofill.inline.common.TextViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setTitleStyle(androidx.autofill.inline.common.TextViewStyle);
+ }
+
+}
+
diff --git a/autofill/autofill/api/res-1.1.0-beta01.txt b/autofill/autofill/api/res-1.1.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/autofill/autofill/api/res-1.1.0-beta01.txt
diff --git a/autofill/autofill/api/restricted_1.1.0-beta01.txt b/autofill/autofill/api/restricted_1.1.0-beta01.txt
new file mode 100644
index 0000000..852dd23
--- /dev/null
+++ b/autofill/autofill/api/restricted_1.1.0-beta01.txt
@@ -0,0 +1,183 @@
+// Signature format: 3.0
+package androidx.autofill {
+
+ public final class HintConstants {
+ method public static String generateSmsOtpHintForCharacterPosition(int);
+ field public static final String AUTOFILL_HINT_BIRTH_DATE_DAY = "birthDateDay";
+ field public static final String AUTOFILL_HINT_BIRTH_DATE_FULL = "birthDateFull";
+ field public static final String AUTOFILL_HINT_BIRTH_DATE_MONTH = "birthDateMonth";
+ field public static final String AUTOFILL_HINT_BIRTH_DATE_YEAR = "birthDateYear";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = "creditCardExpirationYear";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber";
+ field public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode";
+ field public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress";
+ field public static final String AUTOFILL_HINT_GENDER = "gender";
+ field @Deprecated public static final String AUTOFILL_HINT_NAME = "name";
+ field public static final String AUTOFILL_HINT_NEW_PASSWORD = "newPassword";
+ field public static final String AUTOFILL_HINT_NEW_USERNAME = "newUsername";
+ field public static final String AUTOFILL_HINT_PASSWORD = "password";
+ field public static final String AUTOFILL_HINT_PERSON_NAME = "personName";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_FAMILY = "personFamilyName";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_GIVEN = "personGivenName";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_MIDDLE = "personMiddleName";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_MIDDLE_INITIAL = "personMiddleInitial";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_PREFIX = "personNamePrefix";
+ field public static final String AUTOFILL_HINT_PERSON_NAME_SUFFIX = "personNameSuffix";
+ field @Deprecated public static final String AUTOFILL_HINT_PHONE = "phone";
+ field public static final String AUTOFILL_HINT_PHONE_COUNTRY_CODE = "phoneCountryCode";
+ field public static final String AUTOFILL_HINT_PHONE_NATIONAL = "phoneNational";
+ field public static final String AUTOFILL_HINT_PHONE_NUMBER = "phoneNumber";
+ field public static final String AUTOFILL_HINT_PHONE_NUMBER_DEVICE = "phoneNumberDevice";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_COUNTRY = "addressCountry";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_ADDRESS = "extendedAddress";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_POSTAL_CODE = "extendedPostalCode";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_LOCALITY = "addressLocality";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_REGION = "addressRegion";
+ field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_STREET_ADDRESS = "streetAddress";
+ field public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode";
+ field public static final String AUTOFILL_HINT_SMS_OTP = "smsOTPCode";
+ field public static final String AUTOFILL_HINT_USERNAME = "username";
+ }
+
+}
+
+package androidx.autofill.inline {
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class Renderer {
+ method public static android.app.PendingIntent? getAttributionIntent(android.app.slice.Slice);
+ method public static android.os.Bundle getSupportedInlineUiVersionsAsBundle();
+ method public static android.view.View? render(android.content.Context, android.app.slice.Slice, android.os.Bundle);
+ }
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class SuggestionHintConstants {
+ field public static final String SUGGESTION_HINT_CLIPBOARD_CONTENT = "clipboardContent";
+ field public static final String SUGGESTION_HINT_SMART_REPLY = "smartReply";
+ }
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class UiVersions {
+ method public static java.util.List<java.lang.String!> getVersions(android.os.Bundle);
+ method public static androidx.autofill.inline.UiVersions.StylesBuilder newStylesBuilder();
+ field public static final String INLINE_UI_VERSION_1 = "androidx.autofill.inline.ui.version:v1";
+ }
+
+ public static interface UiVersions.Content {
+ method public android.app.slice.Slice getSlice();
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @StringDef({androidx.autofill.inline.UiVersions.INLINE_UI_VERSION_1}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface UiVersions.InlineUiVersion {
+ }
+
+ public static interface UiVersions.Style {
+ }
+
+ public static final class UiVersions.StylesBuilder {
+ method public androidx.autofill.inline.UiVersions.StylesBuilder addStyle(androidx.autofill.inline.UiVersions.Style);
+ method public android.os.Bundle build();
+ }
+
+}
+
+package androidx.autofill.inline.common {
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class ImageViewStyle extends androidx.autofill.inline.common.ViewStyle {
+ }
+
+ public static final class ImageViewStyle.Builder {
+ ctor public ImageViewStyle.Builder();
+ method public androidx.autofill.inline.common.ImageViewStyle build();
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setBackgroundColor(int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setLayoutMargin(int, int, int, int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setMaxHeight(int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setMaxWidth(int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setPadding(int, int, int, int);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setScaleType(android.widget.ImageView.ScaleType);
+ method public androidx.autofill.inline.common.ImageViewStyle.Builder setTintList(android.content.res.ColorStateList);
+ }
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class TextViewStyle extends androidx.autofill.inline.common.ViewStyle {
+ }
+
+ public static final class TextViewStyle.Builder {
+ ctor public TextViewStyle.Builder();
+ method public androidx.autofill.inline.common.TextViewStyle build();
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setBackgroundColor(int);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setLayoutMargin(int, int, int, int);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setPadding(int, int, int, int);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setTextColor(@ColorInt int);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setTextSize(float);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setTextSize(int, float);
+ method public androidx.autofill.inline.common.TextViewStyle.Builder setTypeface(String, int);
+ }
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public class ViewStyle {
+ }
+
+ public static final class ViewStyle.Builder {
+ ctor public ViewStyle.Builder();
+ method public androidx.autofill.inline.common.ViewStyle build();
+ method public androidx.autofill.inline.common.ViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.common.ViewStyle.Builder setBackgroundColor(int);
+ method public androidx.autofill.inline.common.ViewStyle.Builder setLayoutMargin(int, int, int, int);
+ method public androidx.autofill.inline.common.ViewStyle.Builder setPadding(int, int, int, int);
+ }
+
+}
+
+package androidx.autofill.inline.v1 {
+
+ @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class InlineSuggestionUi {
+ method public static androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder newContentBuilder(android.app.PendingIntent);
+ method public static androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder newStyleBuilder();
+ }
+
+ public static final class InlineSuggestionUi.Content implements androidx.autofill.inline.UiVersions.Content {
+ method public android.app.PendingIntent? getAttributionIntent();
+ method public CharSequence? getContentDescription();
+ method public android.graphics.drawable.Icon? getEndIcon();
+ method public final android.app.slice.Slice getSlice();
+ method public android.graphics.drawable.Icon? getStartIcon();
+ method public CharSequence? getSubtitle();
+ method public CharSequence? getTitle();
+ }
+
+ public static final class InlineSuggestionUi.Content.Builder {
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content build();
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setContentDescription(CharSequence);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setEndIcon(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setHints(java.util.List<java.lang.String!>);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setStartIcon(android.graphics.drawable.Icon);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setSubtitle(CharSequence);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setTitle(CharSequence);
+ }
+
+ public static final class InlineSuggestionUi.Style implements androidx.autofill.inline.UiVersions.Style {
+ method public androidx.autofill.inline.common.ViewStyle? getChipStyle();
+ method public androidx.autofill.inline.common.ImageViewStyle? getEndIconStyle();
+ method public int getLayoutDirection();
+ method public androidx.autofill.inline.common.ImageViewStyle? getSingleIconChipIconStyle();
+ method public androidx.autofill.inline.common.ViewStyle? getSingleIconChipStyle();
+ method public androidx.autofill.inline.common.ImageViewStyle? getStartIconStyle();
+ method public androidx.autofill.inline.common.TextViewStyle? getSubtitleStyle();
+ method public androidx.autofill.inline.common.TextViewStyle? getTitleStyle();
+ }
+
+ public static final class InlineSuggestionUi.Style.Builder {
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style build();
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setChipStyle(androidx.autofill.inline.common.ViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setEndIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setLayoutDirection(int);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSingleIconChipIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSingleIconChipStyle(androidx.autofill.inline.common.ViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setStartIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSubtitleStyle(androidx.autofill.inline.common.TextViewStyle);
+ method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setTitleStyle(androidx.autofill.inline.common.TextViewStyle);
+ }
+
+}
+
diff --git a/benchmark/OWNERS b/benchmark/OWNERS
index a69c988..171c5cc 100644
--- a/benchmark/OWNERS
+++ b/benchmark/OWNERS
@@ -1,2 +1,3 @@
ccraik@google.com
dustinlam@google.com
+rahulrav@google.com
diff --git a/benchmark/gradle-plugin/src/main/kotlin/androidx/benchmark/gradle/BenchmarkPlugin.kt b/benchmark/gradle-plugin/src/main/kotlin/androidx/benchmark/gradle/BenchmarkPlugin.kt
index f85b621..ec7b70d 100644
--- a/benchmark/gradle-plugin/src/main/kotlin/androidx/benchmark/gradle/BenchmarkPlugin.kt
+++ b/benchmark/gradle-plugin/src/main/kotlin/androidx/benchmark/gradle/BenchmarkPlugin.kt
@@ -89,25 +89,17 @@
extension.configureTestBuildType(testBuildType)
- // Registering this block as a configureEach callback is only necessary because Studio skips
- // Gradle if there are no changes, which stops this plugin from being re-applied.
- var enabledOutput = false
- project.configurations.configureEach {
- if (!enabledOutput &&
- !project.rootProject.hasProperty("android.injected.invoked.from.ide") &&
- !testInstrumentationArgs.containsKey("androidx.benchmark.output.enable")
- ) {
- enabledOutput = true
+ if (!project.rootProject.hasProperty("android.injected.invoked.from.ide") &&
+ !testInstrumentationArgs.containsKey("androidx.benchmark.output.enable")
+ ) {
+ // NOTE: This argument is checked by ResultWriter to enable CI reports.
+ defaultConfig.testInstrumentationRunnerArgument(
+ "androidx.benchmark.output.enable",
+ "true"
+ )
- // NOTE: This argument is checked by ResultWriter to enable CI reports.
- defaultConfig.testInstrumentationRunnerArgument(
- "androidx.benchmark.output.enable",
- "true"
- )
-
- if (!project.properties[ADDITIONAL_TEST_OUTPUT_KEY].toString().toBoolean()) {
- defaultConfig.testInstrumentationRunnerArgument("no-isolated-storage", "1")
- }
+ if (!project.properties[ADDITIONAL_TEST_OUTPUT_KEY].toString().toBoolean()) {
+ defaultConfig.testInstrumentationRunnerArgument("no-isolated-storage", "1")
}
}
@@ -160,12 +152,13 @@
it.finalizedBy("benchmarkReport")
}
} else {
+ val projectBuildDir = project.buildDir.path
project.tasks.named("connectedAndroidTest").configure {
it.doLast {
Log.logAndDisplay(
Log.LogLevel.INFO,
"Benchmark",
- "Benchmark report files generated at ${project.buildDir}" +
+ "Benchmark report files generated at $projectBuildDir" +
"/outputs/connected_android_test_additional_output"
)
}
diff --git a/benchmark/macro/build.gradle b/benchmark/macro/build.gradle
new file mode 100644
index 0000000..397dc2a
--- /dev/null
+++ b/benchmark/macro/build.gradle
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.Publish
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("kotlin-android")
+}
+
+android {
+ defaultConfig {
+ minSdkVersion 18
+ }
+}
+
+dependencies {
+ // TODO: remove, once we remove the minor usages in CrystalBall
+ implementation(GUAVA_ANDROID)
+
+ implementation("com.android:jank-helper:0.1.0")
+
+ api(JUNIT)
+ api(KOTLIN_STDLIB)
+
+ implementation("androidx.test:rules:1.3.0")
+ implementation("androidx.test:runner:1.3.0")
+ api("androidx.annotation:annotation:1.1.0")
+
+ implementation(ANDROIDX_TEST_EXT_JUNIT)
+ implementation(ANDROIDX_TEST_UIAUTOMATOR)
+}
+
+androidx {
+ name = "Android Benchmark - Macrobenchmark"
+ publish = Publish.NONE
+ mavenGroup = LibraryGroups.BENCHMARK
+ inceptionYear = "2020"
+ description = "Android Benchmark - Macrobenchmark"
+}
diff --git a/benchmark/macro/src/androidTest/AndroidManifest.xml b/benchmark/macro/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..bb07f93
--- /dev/null
+++ b/benchmark/macro/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.benchmark.macro.test">
+</manifest>
\ No newline at end of file
diff --git a/benchmark/macro/src/androidTest/java/JankCollectionHelperTest.kt b/benchmark/macro/src/androidTest/java/JankCollectionHelperTest.kt
new file mode 100644
index 0000000..b27fbf2
--- /dev/null
+++ b/benchmark/macro/src/androidTest/java/JankCollectionHelperTest.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import com.android.helpers.JankCollectionHelper
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class JankCollectionHelperTest {
+ // Setting a minSdkVersion of 27 because JankHelper fails with an error on API 26.
+ // Needs a fix in JankHelper and re-import of prebults.
+ // https://android-build.googleplex.com/builds/tests/view?invocationId=I00300005943166534&redirect=http://sponge2/025964b6-d278-44a7-805c-56d8010935a8
+ @Test
+ @SdkSuppress(minSdkVersion = 27)
+ fun trivialTest() {
+ val helper = JankCollectionHelper()
+ assertTrue(helper.metrics.isNotEmpty())
+ }
+}
diff --git a/benchmark/macro/src/main/AndroidManifest.xml b/benchmark/macro/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a599d46
--- /dev/null
+++ b/benchmark/macro/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest package="androidx.benchmark.macro"/>
diff --git a/biometric/biometric/proguard-rules.pro b/biometric/biometric/proguard-rules.pro
index 7227001..dc9adc0 100644
--- a/biometric/biometric/proguard-rules.pro
+++ b/biometric/biometric/proguard-rules.pro
@@ -41,3 +41,7 @@
class androidx.biometric.KeyguardUtils$Api* {
<methods>;
}
+-keepclassmembernames,allowobfuscation,allowshrinking
+ class androidx.biometric.PackageUtils$Api* {
+ <methods>;
+}
diff --git a/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java b/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
index 3973edd..3c4097d 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
@@ -122,11 +122,6 @@
private static final int REQUEST_CONFIRM_CREDENTIAL = 1;
/**
- * Force the fingerprint dialog to appear for debugging. Must NOT be checked in as {@code true}.
- */
- private static final boolean DEBUG_FORCE_FINGERPRINT = false;
-
- /**
* An executor used by {@link android.hardware.biometrics.BiometricPrompt} to run framework
* code.
*/
@@ -938,23 +933,40 @@
* @return Whether this fragment should display the fingerprint dialog UI.
*/
private boolean isUsingFingerprintDialog() {
- return Build.VERSION.SDK_INT < Build.VERSION_CODES.P || shouldForceFingerprint();
+ return Build.VERSION.SDK_INT < Build.VERSION_CODES.P
+ || isFingerprintDialogNeededForCrypto()
+ || isFingerprintDialogNeededForErrorHandling();
}
/**
- * Checks if this fragment should always display the fingerprint dialog authentication UI,
- * regardless of Android version.
+ * Checks if this fragment should display the fingerprint dialog authentication UI for an
+ * ongoing crypto-based authentication attempt.
*
- * <p>This is needed to force some devices to fall back to fingerprint in order to support
- * strong (crypto-based) authentication.
+ * @return Whether this fragment should display the fingerprint dialog UI.
*
* @see DeviceUtils#shouldUseFingerprintForCrypto(Context, String, String)
*/
- private boolean shouldForceFingerprint() {
+ private boolean isFingerprintDialogNeededForCrypto() {
final FragmentActivity activity = getActivity();
- return DEBUG_FORCE_FINGERPRINT || (activity != null && mViewModel.getCryptoObject() != null
+ return activity != null
+ && mViewModel.getCryptoObject() != null
&& DeviceUtils.shouldUseFingerprintForCrypto(
- activity, Build.MANUFACTURER, Build.MODEL));
+ activity, Build.MANUFACTURER, Build.MODEL);
+ }
+
+ /**
+ * Checks if this fragment should invoke the fingerprint dialog, rather than the framework
+ * biometric prompt, to handle an authentication error.
+ *
+ * @return Whether this fragment should invoke the fingerprint dialog.
+ *
+ * @see DeviceUtils#shouldUseFingerprintForCrypto(Context, String, String)
+ */
+ private boolean isFingerprintDialogNeededForErrorHandling() {
+ // On API 28, BiometricPrompt internally calls FingerprintManager#getErrorString(), which
+ // requires fingerprint hardware to be present (b/151443237).
+ return Build.VERSION.SDK_INT == Build.VERSION_CODES.P
+ && !PackageUtils.hasSystemFeatureFingerprint(getContext());
}
/**
diff --git a/biometric/biometric/src/main/java/androidx/biometric/BiometricManager.java b/biometric/biometric/src/main/java/androidx/biometric/BiometricManager.java
index c827222..e2d9572 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/BiometricManager.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/BiometricManager.java
@@ -195,6 +195,14 @@
boolean isDeviceSecuredWithCredential();
/**
+ * Checks if the current device has a hardware sensor that may be used for fingerprint
+ * authentication.
+ *
+ * @return Whether the device has a fingerprint sensor.
+ */
+ boolean isFingerprintHardwarePresent();
+
+ /**
* Checks if all biometric sensors on the device are known to meet or exceed the security
* requirements for <strong>Class 3</strong> (formerly <strong>Strong</strong>).
*
@@ -242,6 +250,11 @@
}
@Override
+ public boolean isFingerprintHardwarePresent() {
+ return PackageUtils.hasSystemFeatureFingerprint(mContext);
+ }
+
+ @Override
public boolean isStrongBiometricGuaranteed() {
return DeviceUtils.canAssumeStrongBiometrics(mContext, Build.MODEL);
}
@@ -383,7 +396,11 @@
// Non-fingerprint biometrics may be invoked but can't be checked on API 28.
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {
- return canAuthenticateWithFingerprintOrUnknown();
+ // Having fingerprint hardware is a prerequisite, since BiometricPrompt internally
+ // calls FingerprintManager#getErrorString() on API 28 (b/151443237).
+ return mInjector.isFingerprintHardwarePresent()
+ ? canAuthenticateWithFingerprintOrUnknown()
+ : BIOMETRIC_ERROR_NO_HARDWARE;
}
// No non-fingerprint biometric APIs exist prior to API 28.
diff --git a/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java b/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
index 51f12a6..32843ea 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
@@ -133,12 +133,13 @@
/**
* An icon shown on the dialog during authentication.
*/
- private ImageView mFingerprintIcon;
+ @Nullable private ImageView mFingerprintIcon;
/**
* Help text shown below the fingerprint icon on the dialog.
*/
@SuppressWarnings("WeakerAccess") /* synthetic access */
+ @Nullable
TextView mHelpMessageView;
/**
@@ -179,22 +180,25 @@
.inflate(R.layout.fingerprint_dialog_layout, null);
final TextView subtitleView = layout.findViewById(R.id.fingerprint_subtitle);
- final TextView descriptionView = layout.findViewById(R.id.fingerprint_description);
-
- final CharSequence subtitle = mViewModel.getSubtitle();
- if (TextUtils.isEmpty(subtitle)) {
- subtitleView.setVisibility(View.GONE);
- } else {
- subtitleView.setVisibility(View.VISIBLE);
- subtitleView.setText(subtitle);
+ if (subtitleView != null) {
+ final CharSequence subtitle = mViewModel.getSubtitle();
+ if (TextUtils.isEmpty(subtitle)) {
+ subtitleView.setVisibility(View.GONE);
+ } else {
+ subtitleView.setVisibility(View.VISIBLE);
+ subtitleView.setText(subtitle);
+ }
}
- final CharSequence description = mViewModel.getDescription();
- if (TextUtils.isEmpty(description)) {
- descriptionView.setVisibility(View.GONE);
- } else {
- descriptionView.setVisibility(View.VISIBLE);
- descriptionView.setText(description);
+ final TextView descriptionView = layout.findViewById(R.id.fingerprint_description);
+ if (descriptionView != null) {
+ final CharSequence description = mViewModel.getDescription();
+ if (TextUtils.isEmpty(description)) {
+ descriptionView.setVisibility(View.GONE);
+ } else {
+ descriptionView.setVisibility(View.VISIBLE);
+ descriptionView.setText(description);
+ }
}
mFingerprintIcon = layout.findViewById(R.id.fingerprint_icon);
diff --git a/biometric/biometric/src/main/java/androidx/biometric/PackageUtils.java b/biometric/biometric/src/main/java/androidx/biometric/PackageUtils.java
new file mode 100644
index 0000000..9dc2f51
--- /dev/null
+++ b/biometric/biometric/src/main/java/androidx/biometric/PackageUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 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 androidx.biometric;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
+/**
+ * Utilities related to the system {@link PackageManager}.
+ */
+class PackageUtils {
+ // Prevent instantiation.
+ private PackageUtils() {}
+
+ /**
+ * Checks if the current device supports fingerprint authentication.
+ *
+ * @param context The application or activity context.
+ * @return Whether fingerprint is supported.
+ */
+ static boolean hasSystemFeatureFingerprint(@Nullable Context context) {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ && context != null
+ && context.getPackageManager() != null
+ && Api23Impl.hasSystemFeatureFingerprint(context.getPackageManager());
+ }
+
+ /**
+ * Nested class to avoid verification errors for methods introduced in Android 6.0 (API 23).
+ */
+ @RequiresApi(Build.VERSION_CODES.M)
+ private static class Api23Impl {
+ // Prevent instantiation.
+ private Api23Impl() {}
+
+ /**
+ * Checks if the given package manager has support for the fingerprint system feature.
+ *
+ * @param packageManager The system package manager.
+ * @return Whether fingerprint is supported.
+ */
+ static boolean hasSystemFeatureFingerprint(@NonNull PackageManager packageManager) {
+ return packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
+ }
+ }
+}
diff --git a/biometric/biometric/src/test/java/androidx/biometric/BiometricManagerTest.java b/biometric/biometric/src/test/java/androidx/biometric/BiometricManagerTest.java
index 00e61d7..04e665d 100644
--- a/biometric/biometric/src/test/java/androidx/biometric/BiometricManagerTest.java
+++ b/biometric/biometric/src/test/java/androidx/biometric/BiometricManagerTest.java
@@ -55,6 +55,7 @@
frameworkBiometricManager,
true /* isDeviceSecurable */,
true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */,
false /* isStrongBiometricGuaranteed */);
final BiometricManager biometricManager = new BiometricManager(injector);
@@ -73,6 +74,7 @@
frameworkBiometricManager,
true /* isDeviceSecurable */,
true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */,
false /* isStrongBiometricGuaranteed */);
final BiometricManager biometricManager = new BiometricManager(injector);
@@ -92,6 +94,7 @@
frameworkBiometricManager,
true /* isDeviceSecurable */,
true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */,
false /* isStrongBiometricGuaranteed */);
final BiometricManager biometricManager = new BiometricManager(injector);
@@ -111,6 +114,7 @@
frameworkBiometricManager,
true /* isDeviceSecurable */,
true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */,
false /* isStrongBiometricGuaranteed */);
final BiometricManager biometricManager = new BiometricManager(injector);
@@ -130,7 +134,8 @@
final BiometricManager.Injector injector = createInjector(
fingerprintManager,
true /* isDeviceSecurable */,
- true /* isDeviceSecuredWithCredential */);
+ true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */);
final BiometricManager biometricManager = new BiometricManager(injector);
final int authenticators = Authenticators.DEVICE_CREDENTIAL;
@@ -149,6 +154,7 @@
frameworkBiometricManager,
true /* isDeviceSecurable */,
true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */,
false /* isStrongBiometricGuaranteed */);
final BiometricManager biometricManager = new BiometricManager(injector);
@@ -166,7 +172,8 @@
final BiometricManager.Injector injector = createInjector(
fingerprintManager,
true /* isDeviceSecurable */,
- true /* isDeviceSecuredWithCredential */);
+ true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */);
final BiometricManager biometricManager = new BiometricManager(injector);
assertThat(biometricManager.canAuthenticate(0)).isEqualTo(BIOMETRIC_ERROR_NO_HARDWARE);
@@ -183,6 +190,7 @@
frameworkBiometricManager,
false /* isDeviceSecurable */,
false /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */,
false /* isStrongBiometricGuaranteed */);
final BiometricManager biometricManager = new BiometricManager(injector);
@@ -202,7 +210,8 @@
final BiometricManager.Injector injector = createInjector(
fingerprintManager,
false /* isDeviceSecurable */,
- false /* isDeviceSecuredWithCredential */);
+ false /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */);
final BiometricManager biometricManager = new BiometricManager(injector);
final int authenticators = Authenticators.BIOMETRIC_WEAK;
@@ -221,6 +230,7 @@
frameworkBiometricManager,
true /* isDeviceSecurable */,
false /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */,
false /* isStrongBiometricGuaranteed */);
final BiometricManager biometricManager = new BiometricManager(injector);
@@ -240,7 +250,8 @@
final BiometricManager.Injector injector = createInjector(
fingerprintManager,
true /* isDeviceSecurable */,
- false /* isDeviceSecuredWithCredential */);
+ false /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */);
final BiometricManager biometricManager = new BiometricManager(injector);
final int authenticators = Authenticators.BIOMETRIC_WEAK;
@@ -259,6 +270,7 @@
frameworkBiometricManager,
true /* isDeviceSecurable */,
true /* isDeviceSecuredWithCredential */,
+ false /* isFingerprintHardwarePresent */,
false /* isStrongBiometricGuaranteed */);
final BiometricManager biometricManager = new BiometricManager(injector);
@@ -277,7 +289,8 @@
final BiometricManager.Injector injector = createInjector(
fingerprintManager,
true /* isDeviceSecurable */,
- true /* isDeviceSecuredWithCredential */);
+ true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */);
final BiometricManager biometricManager = new BiometricManager(injector);
final int authenticators = Authenticators.BIOMETRIC_WEAK | Authenticators.DEVICE_CREDENTIAL;
@@ -295,6 +308,7 @@
frameworkBiometricManager,
true /* isDeviceSecurable */,
true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */,
true /* isStrongBiometricGuaranteed */);
final BiometricManager biometricManager = new BiometricManager(injector);
@@ -313,6 +327,7 @@
frameworkBiometricManager,
true /* isDeviceSecurable */,
true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */,
false /* isStrongBiometricGuaranteed */);
final BiometricManager biometricManager = new BiometricManager(injector);
@@ -332,7 +347,8 @@
final BiometricManager.Injector injector = createInjector(
fingerprintManager,
true /* isDeviceSecurable */,
- true /* isDeviceSecuredWithCredential */);
+ true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */);
final BiometricManager biometricManager = new BiometricManager(injector);
final int authenticators = Authenticators.BIOMETRIC_STRONG;
@@ -350,7 +366,8 @@
final BiometricManager.Injector injector = createInjector(
fingerprintManager,
true /* isDeviceSecurable */,
- true /* isDeviceSecuredWithCredential */);
+ true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */);
final BiometricManager biometricManager = new BiometricManager(injector);
final int authenticators = Authenticators.BIOMETRIC_STRONG;
@@ -359,6 +376,26 @@
}
@Test
+ @Config(minSdk = Build.VERSION_CODES.P, maxSdk = Build.VERSION_CODES.P)
+ public void testCanAuthenticate_ReturnsError_WhenNoFingerprintHardware_OnApi28() {
+ final androidx.core.hardware.fingerprint.FingerprintManagerCompat fingerprintManager =
+ mock(androidx.core.hardware.fingerprint.FingerprintManagerCompat.class);
+ when(fingerprintManager.isHardwareDetected()).thenReturn(false);
+ when(fingerprintManager.hasEnrolledFingerprints()).thenReturn(false);
+
+ final BiometricManager.Injector injector = createInjector(
+ fingerprintManager,
+ true /* isDeviceSecurable */,
+ true /* isDeviceSecuredWithCredential */,
+ false /* isFingerprintHardwarePresent */);
+
+ final BiometricManager biometricManager = new BiometricManager(injector);
+ final int authenticators = Authenticators.BIOMETRIC_STRONG;
+ assertThat(biometricManager.canAuthenticate(authenticators))
+ .isEqualTo(BIOMETRIC_ERROR_NO_HARDWARE);
+ }
+
+ @Test
@Config(maxSdk = Build.VERSION_CODES.O_MR1)
public void testCanAuthenticate_ReturnsError_WhenFingerprintUnavailable_OnApi27AndBelow() {
final androidx.core.hardware.fingerprint.FingerprintManagerCompat fingerprintManager =
@@ -369,7 +406,8 @@
final BiometricManager.Injector injector = createInjector(
fingerprintManager,
true /* isDeviceSecurable */,
- true /* isDeviceSecuredWithCredential */);
+ true /* isDeviceSecuredWithCredential */,
+ true /* isFingerprintHardwarePresent */);
final BiometricManager biometricManager = new BiometricManager(injector);
final int authenticators = Authenticators.BIOMETRIC_STRONG;
@@ -381,6 +419,7 @@
@Nullable final android.hardware.biometrics.BiometricManager biometricManager,
final boolean isDeviceSecurable,
final boolean isDeviceSecuredWithCredential,
+ final boolean isFingerprintHardwarePresent,
final boolean isStrongBiometricGuaranteed) {
return new BiometricManager.Injector() {
@@ -408,6 +447,11 @@
}
@Override
+ public boolean isFingerprintHardwarePresent() {
+ return isFingerprintHardwarePresent;
+ }
+
+ @Override
public boolean isStrongBiometricGuaranteed() {
return isStrongBiometricGuaranteed;
}
@@ -418,7 +462,8 @@
@Nullable final androidx.core.hardware.fingerprint.FingerprintManagerCompat
fingerprintManager,
final boolean isDeviceSecurable,
- final boolean isDeviceSecuredWithCredential) {
+ final boolean isDeviceSecuredWithCredential,
+ final boolean isFingerprintHardwarePresent) {
return new BiometricManager.Injector() {
@Override
@@ -445,6 +490,11 @@
}
@Override
+ public boolean isFingerprintHardwarePresent() {
+ return isFingerprintHardwarePresent;
+ }
+
+ @Override
public boolean isStrongBiometricGuaranteed() {
return false;
}
diff --git a/biometric/biometric/src/test/java/androidx/biometric/PackageUtilsTest.java b/biometric/biometric/src/test/java/androidx/biometric/PackageUtilsTest.java
new file mode 100644
index 0000000..b597082
--- /dev/null
+++ b/biometric/biometric/src/test/java/androidx/biometric/PackageUtilsTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 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 androidx.biometric;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+@LargeTest
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class PackageUtilsTest {
+ @Mock private Context mContext;
+ @Mock private PackageManager mPackageManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ @Config(maxSdk = Build.VERSION_CODES.LOLLIPOP_MR1)
+ public void testHasSystemFeatureFingerprint_ReturnsFalse_OnApi22AndBelow() {
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(anyString())).thenReturn(true);
+ assertThat(PackageUtils.hasSystemFeatureFingerprint(mContext)).isFalse();
+ }
+
+ @Test
+ @Config(minSdk = Build.VERSION_CODES.M)
+ public void testHasSystemFeatureFingerprint_ReturnsFalse_WhenContextIsNull() {
+ assertThat(PackageUtils.hasSystemFeatureFingerprint(null)).isFalse();
+ }
+
+ @Test
+ @Config(minSdk = Build.VERSION_CODES.M)
+ public void testHasSystemFeatureFingerprint_ReturnsFalse_WhenPackageManagerIsNull() {
+ when(mContext.getPackageManager()).thenReturn(null);
+ assertThat(PackageUtils.hasSystemFeatureFingerprint(mContext)).isFalse();
+ }
+
+ @Test
+ @Config(minSdk = Build.VERSION_CODES.M)
+ public void testHasSystemFeatureFingerprint_ReturnsFalse_WhenPackageManagerReturnsFalse() {
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(false);
+ assertThat(PackageUtils.hasSystemFeatureFingerprint(mContext)).isFalse();
+ }
+
+ @Test
+ @Config(minSdk = Build.VERSION_CODES.M)
+ public void testHasSystemFeatureFingerprint_ReturnsTrue_WhenPackageManagerReturnsTrue() {
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
+ assertThat(PackageUtils.hasSystemFeatureFingerprint(mContext)).isTrue();
+ }
+}
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXExtension.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXExtension.kt
index 56e533a..d19314f 100644
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXExtension.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/AndroidXExtension.kt
@@ -36,6 +36,7 @@
field = value
chooseProjectVersion()
}
+ private val ALLOWED_EXTRA_PREFIXES = listOf("-alpha", "-beta", "-rc", "-dev", "-SNAPSHOT")
private fun chooseProjectVersion() {
val version: Version
@@ -49,10 +50,12 @@
") whose mavenGroup already specifies forcedVersion (" + groupVersion +
")")
} else {
+ verifyVersionExtraFormat(mavenVersion)
version = mavenVersion
}
} else {
if (groupVersion != null) {
+ verifyVersionExtraFormat(groupVersion)
version = groupVersion
} else {
return
@@ -65,6 +68,31 @@
versionIsSet = true
}
+ private fun verifyVersionExtraFormat(version: Version) {
+ val extra = version.extra
+ if (extra != null) {
+ if (!version.isSnapshot()) {
+ if (ALLOWED_EXTRA_PREFIXES.any { extra.startsWith(it) }) {
+ for (potentialPrefix in ALLOWED_EXTRA_PREFIXES) {
+ if (extra.startsWith(potentialPrefix)) {
+ val secondExtraPart = extra.removePrefix(
+ potentialPrefix)
+ if (secondExtraPart.toIntOrNull() == null) {
+ throw IllegalArgumentException("Version $version is not" +
+ " a properly formatted version, please ensure that " +
+ "$potentialPrefix is followed by a number only")
+ }
+ }
+ }
+ } else {
+ throw IllegalArgumentException("Version $version is not a proper " +
+ "version, version suffixes following major.minor.patch should " +
+ "be one of ${ALLOWED_EXTRA_PREFIXES.joinToString(", ")}")
+ }
+ }
+ }
+ }
+
private fun isGroupVersionOverrideAllowed(): Boolean {
// Grant an exception to the same-version-group policy for artifacts that haven't shipped a
// stable API surface, e.g. 1.0.0-alphaXX, to allow for rapid early-stage development.
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
index ba65de1..9a201a2 100644
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
@@ -81,7 +81,7 @@
* Specifies to validate that the build doesn't generate any unrecognized messages
* This prevents developers from inadvertently adding new warnings to the build output
*/
-const val VALIDATE_NO_EXTRA_MESSAGES = "androidx.validateNoExtraMessages"
+const val VALIDATE_NO_UNRECOGNIZED_MESSAGES = "androidx.validateNoUnrecognizedMessages"
val ALL_ANDROIDX_PROPERTIES = setOf(
ALL_WARNINGS_AS_ERRORS,
@@ -91,7 +91,7 @@
STUDIO_TYPE,
SUMMARIZE_STANDARD_ERROR,
TEST_FAILURES_DO_NOT_FAIL_TEST_TASK,
- VALIDATE_NO_EXTRA_MESSAGES,
+ VALIDATE_NO_UNRECOGNIZED_MESSAGES,
WRITE_VERSIONED_API_FILES,
AffectedModuleDetector.CHANGED_PROJECTS_ARG,
AffectedModuleDetector.ENABLE_ARG,
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
index d7c006d..d6881ff 100644
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
@@ -285,6 +285,7 @@
check(!excludes.contains("/META-INF/*.kotlin_module"))
}
+ project.verifyLintProjectSettings(androidXExtension)
project.configureSourceJarForAndroid(libraryExtension)
project.configureVersionFileWriter(libraryExtension, androidXExtension)
@@ -335,6 +336,7 @@
private fun configureWithJavaPlugin(project: Project, extension: AndroidXExtension) {
project.configureErrorProneForJava()
project.configureSourceJarForJava()
+ project.verifyLintProjectSettings(extension)
// Force Java 1.8 source- and target-compatibilty for all Java libraries.
val convention = project.convention.getPlugin<JavaPluginConvention>()
@@ -702,6 +704,29 @@
}
}
+ private fun Project.verifyLintProjectSettings(extension: AndroidXExtension) {
+ if (isLint()) {
+ project.afterEvaluate {
+ if (extension.publish != Publish.NONE) {
+ throw IllegalArgumentException("Invalid Publish `${extension.publish}` for " +
+ "lint project, should be `NONE` instead. Lint projects are meant to " +
+ "be published through lintPublish as part of an aar, as such, lint " +
+ "projects should always set their publish to <Publish.NONE>")
+ }
+ if (extension.toolingProject != true) {
+ throw IllegalArgumentException("Invalid toolingProject settings: `${extension
+ .toolingProject}` for lint project, should be `true` instead. Lint " +
+ "projects are considered tooling projects.")
+ }
+ if (extension.compilationTarget != CompilationTarget.HOST) {
+ throw IllegalArgumentException("Invalid compilation target: " +
+ "`${extension.compilationTarget}` for lint project, should be " +
+ "`CompilationTarget.HOST` instead.")
+ }
+ }
+ }
+ }
+
private fun Project.configureJacoco() {
apply(plugin = "jacoco")
configure<JacocoPluginExtension> {
@@ -849,3 +874,12 @@
it.dependsOn(task)
}
}
+
+/**
+ * This isn't ideal for figuring out if a project is a lint project that's meant to be published
+ * using lintPublish, however it's a reasonable estimate for now until we have a better way.
+ * @owengray plans to refine this function.
+ */
+fun Project.isLint(): Boolean {
+ return project.name.endsWith("-lint")
+}
diff --git a/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
index d17cf46..66e9a20 100644
--- a/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
@@ -459,7 +459,7 @@
description = "Zips $ruleName Java documentation (generated via Doclava in the " +
"style of d.android.com) into $destinationFile"
doLast {
- logger.quiet("'Wrote API reference to $destinationFile")
+ logger.info("'Wrote API reference to $destinationFile")
}
}
}
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
index 7a2427f..43b5e21 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
@@ -41,7 +41,6 @@
val CONTENTPAGER = LibraryGroup("androidx.contentpager", LibraryVersions.CONTENTPAGER)
val COORDINATORLAYOUT = LibraryGroup("androidx.coordinatorlayout",
LibraryVersions.COORDINATORLAYOUT)
- val COMPOSE = LibraryGroup("androidx.compose", null)
val CORE = LibraryGroup("androidx.core", null)
val CURSORADAPTER = LibraryGroup("androidx.cursoradapter", LibraryVersions.CURSORADAPTER)
val CUSTOMVIEW = LibraryGroup("androidx.customview", LibraryVersions.CUSTOMVIEW)
@@ -109,6 +108,7 @@
object Compose {
val ANIMATION = LibraryGroup("androidx.compose.animation", null)
+ val COMPILER = LibraryGroup("androidx.compose.compiler", null)
val FOUNDATION = LibraryGroup("androidx.compose.foundation", null)
val MATERIAL = LibraryGroup("androidx.compose.material", null)
val NAVIGATION = LibraryGroup("androidx.compose.navigation", null)
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index 66afc79..f6d4ffa 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -20,7 +20,7 @@
* The list of versions codes of all the libraries in this project.
*/
object LibraryVersions {
- val ACTIVITY = Version("1.2.0-alpha09")
+ val ACTIVITY = Version("1.2.0-beta01")
val ADS_IDENTIFIER = Version("1.0.0-alpha04")
val ANNOTATION = Version("1.2.0-alpha02")
val ANNOTATION_EXPERIMENTAL = Version("1.1.0-alpha01")
@@ -30,16 +30,16 @@
val ARCH_CORE_TESTING = ARCH_CORE
val ARCH_RUNTIME = Version("2.2.0-alpha01")
val ASYNCLAYOUTINFLATER = Version("1.1.0-alpha01")
- val AUTOFILL = Version("1.1.0-alpha02")
+ val AUTOFILL = Version("1.1.0-beta01")
val BENCHMARK = Version("1.1.0-alpha02")
val BIOMETRIC = Version("1.1.0-alpha03")
val BROWSER = Version("1.3.0-alpha06")
val BUILDSRC_TESTS = Version("1.0.0-alpha01")
- val CAMERA = Version("1.0.0-beta09")
- val CAMERA_EXTENSIONS = Version("1.0.0-alpha16")
+ val CAMERA = Version("1.0.0-beta10")
+ val CAMERA_EXTENSIONS = Version("1.0.0-alpha17")
val CAMERA_PIPE = Version("1.0.0-alpha01")
val CAMERA_VIDEO = Version("1.0.0-alpha01")
- val CAMERA_VIEW = Version("1.0.0-alpha16")
+ val CAMERA_VIEW = Version("1.0.0-alpha17")
val CARDVIEW = Version("1.1.0-alpha01")
val COLLECTION = Version("1.2.0-alpha01")
val CONTENTPAGER = Version("1.1.0-alpha01")
@@ -47,7 +47,7 @@
val COMPOSE_NAVIGATION = Version("0.1.0-dev01")
val CONTENTACCESS = Version("1.0.0-alpha01")
val COORDINATORLAYOUT = Version("1.2.0-alpha01")
- val CORE = Version("1.5.0-alpha03")
+ val CORE = Version("1.5.0-alpha04")
val CORE_ANIMATION = Version("1.0.0-alpha03")
val CORE_ANIMATION_TESTING = Version("1.0.0-alpha03")
val CORE_APPDIGEST = Version("1.0.0-alpha01")
@@ -62,7 +62,7 @@
val EMOJI = Version("1.2.0-alpha02")
val ENTERPRISE = Version("1.1.0-alpha02")
val EXIFINTERFACE = Version("1.4.0-alpha01")
- val FRAGMENT = Version("1.3.0-alpha09")
+ val FRAGMENT = Version("1.3.0-beta01")
val FUTURES = Version("1.2.0-alpha01")
val GRIDLAYOUT = Version("1.1.0-alpha01")
val HEIFWRITER = Version("1.1.0-alpha01")
diff --git a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
index e61f8fd..3d69a0d 100644
--- a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
@@ -40,6 +40,7 @@
prebuilts(LibraryGroups.ASYNCLAYOUTINFLATER, "1.0.0")
prebuilts(LibraryGroups.AUTOFILL, "1.1.0-alpha02")
ignore(LibraryGroups.BENCHMARK.group, "benchmark-gradle-plugin")
+ ignore(LibraryGroups.BENCHMARK.group, "benchmark-macro")
prebuilts(LibraryGroups.BENCHMARK, "1.1.0-alpha01")
prebuilts(LibraryGroups.BIOMETRIC, "biometric", "1.1.0-alpha02")
prebuilts(LibraryGroups.BROWSER, "1.3.0-alpha05")
@@ -172,7 +173,9 @@
* Rule set used to generate tip-of-tree documentation, typically for local and pre-submit use.
*/
val TIP_OF_TREE = docsRules("tipOfTree", true) {
- ignore(LibraryGroups.COMPOSE.group)
+ // Doclava breaks when generating docs for the Compiler due to some missing (?) Kotlin
+ // classes - this can probably be removed after we remove Doclava support.
+ ignore(LibraryGroups.Compose.COMPILER.group)
default(TipOfTree)
}
diff --git a/buildSrc/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt b/buildSrc/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
index 03eec98..e8fc778 100644
--- a/buildSrc/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
@@ -99,7 +99,7 @@
// Only verify configurations that are exported to POM. In an ideal world, this would be an
// inclusion derived from the mappings used by the Maven Publish Plugin; however, since we
// don't have direct access to those, this should remain an exclusion list.
- var name = configuration.name
+ val name = configuration.name
// Don't check any Android-specific variants of Java plugin configurations -- releaseApi for
// api, debugImplementation for implementation, etc. -- or test configurations.
@@ -108,10 +108,11 @@
if (name.startsWith("release")) return false
if (name.startsWith("test")) return false
- // Don't check any tooling configurations (except lint!).
+ // Don't check any tooling configurations.
if (name == "annotationProcessor") return false
if (name == "errorprone") return false
if (name.startsWith("jacoco")) return false
+ if (name.startsWith("lint")) return false
if (name == "metalava") return false
return true
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
index a123998..ccec494 100644
--- a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
@@ -72,7 +72,7 @@
"com.squareup:kotlinpoet-classinspector-elements:1.4.0"
const val KOTLIN_COMPILE_TESTING = "com.github.tschuchortdev:kotlin-compile-testing:1.2.10"
const val KOTLIN_COMPILE_TESTING_KSP = "com.github.tschuchortdev:kotlin-compile-testing-ksp:1.2.10"
-const val KSP_VERSION = "1.4.0-dev-experimental-20200828"
+const val KSP_VERSION = "1.4.0-dev-experimental-20200914"
const val KOTLIN_KSP_API = "org.jetbrains.kotlin:kotlin-symbol-processing-api:$KSP_VERSION"
const val KOTLIN_KSP = "org.jetbrains.kotlin:kotlin-ksp:$KSP_VERSION"
const val KOTLIN_GRADLE_PLUGIN = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0-rc"
diff --git a/busytown/androidx.sh b/busytown/androidx.sh
index eedda4e..05e7732 100755
--- a/busytown/androidx.sh
+++ b/busytown/androidx.sh
@@ -6,9 +6,9 @@
cd "$(dirname $0)"
# Run Gradle
-impl/build.sh --no-daemon listTaskOutputs "$@"
+impl/build.sh --no-daemon listTaskOutputs -Pandroidx.validateNoUnrecognizedMessages "$@"
impl/build.sh allProperties "$@" >/dev/null
-impl/build.sh --no-daemon buildOnServer checkExternalLicenses \
+impl/build.sh --no-daemon buildOnServer -Pandroidx.validateNoUnrecognizedMessages checkExternalLicenses \
-PverifyUpToDate \
-Pandroidx.coverageEnabled=true \
-Pandroidx.allWarningsAsErrors --profile "$@"
diff --git a/busytown/impl/build.sh b/busytown/impl/build.sh
index 5ea576e..aee363c 100755
--- a/busytown/impl/build.sh
+++ b/busytown/impl/build.sh
@@ -15,6 +15,5 @@
# cd to checkout root
cd "$SCRIPT_DIR/../../../.."
-
OUT_DIR=out/ui DIST_DIR=$DIST_DIR/ui ANDROID_HOME=./prebuilts/fullsdk-linux frameworks/support/ui/gradlew -p frameworks/support/ui --stacktrace -Pandroidx.summarizeStderr "$@"
OUT_DIR=out DIST_DIR=$DIST_DIR ANDROID_HOME=./prebuilts/fullsdk-linux frameworks/support/gradlew -p frameworks/support --stacktrace -Pandroidx.summarizeStderr "$@"
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraPipeCameraFactory.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraPipeCameraFactory.kt
index ce33ae9..adcd429 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraPipeCameraFactory.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraPipeCameraFactory.kt
@@ -38,8 +38,9 @@
init {
if (DEBUG) {
Log.d(
- TAG, "Initialized CameraFactory [Context: $context, " +
- "ThreadConfig: $threadConfig, CameraPipe: $cameraPipe]"
+ TAG,
+ "Initialized CameraFactory [Context: $context, " +
+ "ThreadConfig: $threadConfig, CameraPipe: $cameraPipe]"
)
}
}
diff --git a/camera/camera-camera2-pipe/build.gradle b/camera/camera-camera2-pipe/build.gradle
index 4a76775..f61ac0a 100644
--- a/camera/camera-camera2-pipe/build.gradle
+++ b/camera/camera-camera2-pipe/build.gradle
@@ -70,6 +70,13 @@
testOptions.unitTests.includeAndroidResources = true
}
+kapt {
+ javacOptions {
+ option("-Adagger.fastInit=enabled")
+ option("-Adagger.fullBindingGraphValidation=ERROR")
+ }
+}
+
// Create jarjar artifact for all variants (debug/release)
android.libraryVariants.all { variant ->
def variantName = variant.name
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraGraphComponent.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraGraphComponent.kt
index a1c4460..c95132b 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraGraphComponent.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraGraphComponent.kt
@@ -38,7 +38,8 @@
@Subcomponent(
modules = [
CameraGraphModules::class,
- CameraGraphConfigModule::class]
+ CameraGraphConfigModule::class
+ ]
)
interface CameraGraphComponent {
fun cameraGraph(): CameraGraph
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraPipeComponent.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraPipeComponent.kt
index 1849443..f8ee3cc 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraPipeComponent.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraPipeComponent.kt
@@ -119,7 +119,7 @@
val globalScope = CoroutineScope(
cameraDispatcher.plus(
CoroutineName
- ("CXCP-Pipe")
+ ("CXCP-Pipe")
)
)
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/Debug.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/Debug.kt
index cf44015..277b27e 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/Debug.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/Debug.kt
@@ -97,8 +97,8 @@
val capabilities = metadata[REQUEST_AVAILABLE_CAPABILITIES]
val cameraType = if (capabilities != null &&
capabilities.contains(
- REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
- )
+ REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
+ )
) {
"Logical"
} else {
@@ -123,9 +123,11 @@
append("Default Parameters: (None)")
} else {
append("Default Parameters:\n")
- for (parameter in graphConfig.defaultParameters.filter {
- it is CaptureRequest.Key<*>
- }) {
+ for (
+ parameter in graphConfig.defaultParameters.filter {
+ it is CaptureRequest.Key<*>
+ }
+ ) {
append(" ")
append((parameter.key as CaptureRequest.Key<*>).name.padEnd(50, ' '))
append(parameter.value)
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/GraphProcessor.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/GraphProcessor.kt
index 19e67ff..21fe62d 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/GraphProcessor.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/GraphProcessor.kt
@@ -123,7 +123,7 @@
} else {
warn {
"Refusing to detach $requestProcessor. " +
- "It is different from $_requestProcessor"
+ "It is different from $_requestProcessor"
}
}
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/SessionFactory.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/SessionFactory.kt
index 09459db..dec2ca9 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/SessionFactory.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/SessionFactory.kt
@@ -138,7 +138,7 @@
} catch (e: Throwable) {
Log.warn {
"Failed to create reprocessable captures session from $cameraDevice for" +
- " $virtualSessionState!"
+ " $virtualSessionState!"
}
virtualSessionState.disconnect()
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/StreamMap.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/StreamMap.kt
index 94e67db..a7f435a 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/StreamMap.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/StreamMap.kt
@@ -58,11 +58,13 @@
val hardwareLevel = cameraMetadata[INFO_SUPPORTED_HARDWARE_LEVEL]
val deferredStreamsSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
- graphConfig.operatingMode == CameraGraph.OperatingMode.NORMAL &&
- hardwareLevel != INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY &&
- hardwareLevel != INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED &&
- (Build.VERSION.SDK_INT < Build.VERSION_CODES.P ||
- hardwareLevel != INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL)
+ graphConfig.operatingMode == CameraGraph.OperatingMode.NORMAL &&
+ hardwareLevel != INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY &&
+ hardwareLevel != INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED &&
+ (
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.P ||
+ hardwareLevel != INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL
+ )
for (streamConfig in graphConfig.streams) {
// Using an inline class generates a synthetic constructor
@@ -79,8 +81,10 @@
if (deferredStreamsSupported &&
streamConfig.deferrable &&
- (streamConfig.type == StreamType.SURFACE_TEXTURE ||
- streamConfig.type == StreamType.SURFACE_VIEW)
+ (
+ streamConfig.type == StreamType.SURFACE_TEXTURE ||
+ streamConfig.type == StreamType.SURFACE_VIEW
+ )
) {
deferrableStreamBuilder.add(stream.id)
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCamera.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCamera.kt
index baa41dd..30822fb 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCamera.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCamera.kt
@@ -220,7 +220,7 @@
"Opened $cameraId in ${attemptDuration.formatNanoTime()}"
} else {
"Opened $cameraId in ${attemptDuration.formatNanoTime()} " +
- "(${totalDuration.formatNanoTime()} total) after $attemptNumber attempts."
+ "(${totalDuration.formatNanoTime()} total) after $attemptNumber attempts."
}
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCameraManager.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCameraManager.kt
index c69a306..f865202 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCameraManager.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCameraManager.kt
@@ -349,7 +349,8 @@
timeout = 1000,
callback = {
channel.offer(RequestClose(this))
- })
+ }
+ )
init {
listenerJob = scope.launch {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualSessionState.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualSessionState.kt
index e9ab5aa..ba041d5 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualSessionState.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualSessionState.kt
@@ -280,7 +280,7 @@
Log.info {
val finalizationTime = Metrics.monotonicNanos() - finalizedStartTime
"Finalized ${pendingOutputs.map { it.key }} for $this in " +
- finalizationTime.formatNanoTime()
+ finalizationTime.formatNanoTime()
}
tryResubmit = true
}
@@ -329,7 +329,7 @@
if (deferred.isNotEmpty()) {
Log.info {
"Created $this with ${surfaces.keys.toList()}. " +
- "Waiting to finalize ${deferred.keys.toList()}"
+ "Waiting to finalize ${deferred.keys.toList()}"
}
pendingOutputMap = deferred
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/CaptureSession.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/CaptureSession.kt
index b5a9a42..50cecfa 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/CaptureSession.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/CaptureSession.kt
@@ -313,8 +313,8 @@
override fun finalizeOutputConfigurations(outputConfigs: List<OutputConfigurationWrapper>) {
check(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
"Attempting to call finalizeOutputConfigurations before O is not supported and may " +
- "lead to to unexpected behavior if an application is expects this call to " +
- "succeed."
+ "lead to to unexpected behavior if an application is expects this call to " +
+ "succeed."
}
rethrowCamera2Exceptions {
@@ -362,7 +362,7 @@
// exception that can be ignored.
Log.warn {
"Failed to createHighSpeedRequestList from $device because the output surface" +
- " was destroyed before calling createHighSpeedRequestList."
+ " was destroyed before calling createHighSpeedRequestList."
}
throw ObjectUnavailableException(e)
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/Configuration.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/Configuration.kt
index 0761aeb..2324ff4 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/Configuration.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/Configuration.kt
@@ -149,7 +149,7 @@
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
throw IllegalStateException(
"Deferred OutputConfigurations are not supported on API " +
- "${Build.VERSION.SDK_INT} (requires API ${Build.VERSION_CODES.O})"
+ "${Build.VERSION.SDK_INT} (requires API ${Build.VERSION_CODES.O})"
)
}
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/SessionFactoryTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/SessionFactoryTest.kt
index 6eb59f3..a6a33e50 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/SessionFactoryTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/SessionFactoryTest.kt
@@ -43,7 +43,8 @@
@CameraGraphScope
@Component(
modules = [
- FakeCameras.FakeCameraGraphModule::class
+ FakeCameras.FakeCameraGraphModule::class,
+ FakeCameras.FakeCameraPipeModule::class
]
)
interface CameraSessionTestComponent {
@@ -71,8 +72,8 @@
@Test
fun canCreateSessionFactoryTestComponent() = runBlockingTest {
val component: CameraSessionTestComponent = DaggerCameraSessionTestComponent.builder()
- .fakeCameraGraphModule(
- FakeCameras.FakeCameraGraphModule(context, testCamera)
+ .fakeCameraPipeModule(
+ FakeCameras.FakeCameraPipeModule(context, testCamera)
)
.build()
@@ -83,8 +84,8 @@
@Test
fun createCameraCaptureSession() = runBlockingTest {
val component: CameraSessionTestComponent = DaggerCameraSessionTestComponent.builder()
- .fakeCameraGraphModule(
- FakeCameras.FakeCameraGraphModule(context, testCamera)
+ .fakeCameraPipeModule(
+ FakeCameras.FakeCameraPipeModule(context, testCamera)
)
.build()
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/VirtualCameraTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/VirtualCameraTest.kt
index edc640a..7164298 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/VirtualCameraTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/VirtualCameraTest.kt
@@ -83,11 +83,14 @@
// additional events from being passed to the virtual camera instance.
val virtualCamera = VirtualCameraState(cameraId)
val cameraState = flowOf(CameraStateOpen(testCamera.cameraDeviceWrapper))
- virtualCamera.connect(cameraState, object : Token {
- override fun release(): Boolean {
- return true
+ virtualCamera.connect(
+ cameraState,
+ object : Token {
+ override fun release(): Boolean {
+ return true
+ }
}
- })
+ )
virtualCamera.state.first { it !is CameraStateUnopened }
@@ -122,11 +125,14 @@
}
}
- virtualCamera.connect(states.asFlow(), object : Token {
- override fun release(): Boolean {
- return true
+ virtualCamera.connect(
+ states.asFlow(),
+ object : Token {
+ override fun release(): Boolean {
+ return true
+ }
}
- })
+ )
// Suspend until the state is closed
virtualCamera.state.first { it is CameraStateClosed }
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameras.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameras.kt
index 029766f0..774a8ce 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameras.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameras.kt
@@ -184,13 +184,8 @@
/**
* Utility module for testing the Dagger generated graph with a a reasonable default config.
*/
- @Module(
- includes = [
- CameraPipeModules::class,
- CameraGraphModules::class
- ]
- )
- class FakeCameraGraphModule(
+ @Module(includes = [CameraPipeModules::class])
+ class FakeCameraPipeModule(
private val context: Context,
private val fakeCamera: FakeCamera
) {
@@ -213,4 +208,7 @@
template = RequestTemplate(0)
)
}
+
+ @Module(includes = [CameraGraphModules::class])
+ class FakeCameraGraphModule
}
diff --git a/camera/camera-camera2/api/1.0.0-beta10.txt b/camera/camera-camera2/api/1.0.0-beta10.txt
new file mode 100644
index 0000000..c4e0698
--- /dev/null
+++ b/camera/camera-camera2/api/1.0.0-beta10.txt
@@ -0,0 +1,9 @@
+// Signature format: 3.0
+package androidx.camera.camera2 {
+
+ public final class Camera2Config {
+ method public static androidx.camera.core.CameraXConfig defaultConfig();
+ }
+
+}
+
diff --git a/camera/camera-camera2/api/public_plus_experimental_1.0.0-beta10.txt b/camera/camera-camera2/api/public_plus_experimental_1.0.0-beta10.txt
new file mode 100644
index 0000000..d706ed6
--- /dev/null
+++ b/camera/camera-camera2/api/public_plus_experimental_1.0.0-beta10.txt
@@ -0,0 +1,41 @@
+// Signature format: 3.0
+package androidx.camera.camera2 {
+
+ public final class Camera2Config {
+ method public static androidx.camera.core.CameraXConfig defaultConfig();
+ }
+
+}
+
+package androidx.camera.camera2.interop {
+
+ @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2CameraFilter {
+ method public static androidx.camera.core.CameraFilter createCameraFilter(androidx.camera.camera2.interop.Camera2CameraFilter.Camera2Filter);
+ }
+
+ public static interface Camera2CameraFilter.Camera2Filter {
+ method public java.util.LinkedHashMap<java.lang.String!,android.hardware.camera2.CameraCharacteristics!> filter(java.util.LinkedHashMap<java.lang.String!,android.hardware.camera2.CameraCharacteristics!>);
+ }
+
+ @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2CameraInfo {
+ method public static androidx.camera.camera2.interop.Camera2CameraInfo fromCameraInfo(androidx.camera.core.CameraInfo);
+ method public <T> T? getCameraCharacteristic(android.hardware.camera2.CameraCharacteristics.Key<T!>);
+ method public String getCameraId();
+ }
+
+ @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2Interop {
+ }
+
+ public static final class Camera2Interop.Extender<T> {
+ ctor public Camera2Interop.Extender(androidx.camera.core.ExtendableBuilder<T!>);
+ method public <ValueT> androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setCaptureRequestOption(android.hardware.camera2.CaptureRequest.Key<ValueT!>, ValueT);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setDeviceStateCallback(android.hardware.camera2.CameraDevice.StateCallback);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setSessionCaptureCallback(android.hardware.camera2.CameraCaptureSession.CaptureCallback);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setSessionStateCallback(android.hardware.camera2.CameraCaptureSession.StateCallback);
+ }
+
+ @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCamera2Interop {
+ }
+
+}
+
diff --git a/camera/camera-camera2/api/res-1.0.0-beta10.txt b/camera/camera-camera2/api/res-1.0.0-beta10.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-camera2/api/res-1.0.0-beta10.txt
diff --git a/camera/camera-camera2/api/restricted_1.0.0-beta10.txt b/camera/camera-camera2/api/restricted_1.0.0-beta10.txt
new file mode 100644
index 0000000..c4e0698
--- /dev/null
+++ b/camera/camera-camera2/api/restricted_1.0.0-beta10.txt
@@ -0,0 +1,9 @@
+// Signature format: 3.0
+package androidx.camera.camera2 {
+
+ public final class Camera2Config {
+ method public static androidx.camera.core.CameraXConfig defaultConfig();
+ }
+
+}
+
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java
index fed9c13..5a3d6d4 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
-import android.Manifest;
import android.app.Instrumentation;
import android.content.Context;
import android.hardware.camera2.CameraCharacteristics;
@@ -41,7 +40,6 @@
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.GrantPermissionRule;
import com.google.common.util.concurrent.ListenableFuture;
@@ -49,6 +47,7 @@
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -80,8 +79,7 @@
}
@Rule
- public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(
- Manifest.permission.CAMERA);
+ public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
private CameraUseCaseAdapter mCamera;
private UseCase mBoundUseCase;
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
index 9c5c2f8..629c6f6 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
@@ -254,7 +254,7 @@
public void defaultAspectRatioWillBeSet_whenTargetResolutionIsNotSet() {
ImageAnalysis useCase = new ImageAnalysis.Builder().build();
mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, mCameraSelector, useCase);
- ImageOutputConfig config = (ImageOutputConfig) useCase.getUseCaseConfig();
+ ImageOutputConfig config = (ImageOutputConfig) useCase.getCurrentConfig();
assertThat(config.getTargetAspectRatio()).isEqualTo(AspectRatio.RATIO_4_3);
}
@@ -264,13 +264,13 @@
ImageAnalysis useCase = new ImageAnalysis.Builder().setTargetResolution(
GUARANTEED_RESOLUTION).build();
- assertThat(useCase.getUseCaseConfig().containsOption(
+ assertThat(useCase.getCurrentConfig().containsOption(
ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)).isFalse();
mCamera = CameraUtil.createCameraAndAttachUseCase(mContext,
CameraSelector.DEFAULT_BACK_CAMERA, useCase);
- assertThat(useCase.getUseCaseConfig().containsOption(
+ assertThat(useCase.getCurrentConfig().containsOption(
ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)).isFalse();
}
@@ -292,7 +292,7 @@
// Updates target rotation from ROTATION_0 to ROTATION_90.
imageAnalysis.setTargetRotation(Surface.ROTATION_90);
- ImageOutputConfig newConfig = (ImageOutputConfig) imageAnalysis.getUseCaseConfig();
+ ImageOutputConfig newConfig = (ImageOutputConfig) imageAnalysis.getCurrentConfig();
Size expectedTargetResolution = new Size(GUARANTEED_RESOLUTION.getHeight(),
GUARANTEED_RESOLUTION.getWidth());
@@ -337,7 +337,7 @@
@Test
public void useCaseConfigCanBeReset_afterUnbind() {
final ImageAnalysis useCase = new ImageAnalysis.Builder().build();
- UseCaseConfig<?> initialConfig = useCase.getUseCaseConfig();
+ UseCaseConfig<?> initialConfig = useCase.getCurrentConfig();
mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, mCameraSelector, useCase);
@@ -345,7 +345,7 @@
mCamera.removeUseCases(Collections.singleton(useCase));
});
- UseCaseConfig<?> configAfterUnbinding = useCase.getUseCaseConfig();
+ UseCaseConfig<?> configAfterUnbinding = useCase.getCurrentConfig();
assertThat(initialConfig.equals(configAfterUnbinding)).isTrue();
}
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
index 7fc0216..34dd3e5 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
@@ -778,7 +778,7 @@
public void defaultAspectRatioWillBeSet_whenTargetResolutionIsNotSet() {
ImageCapture useCase = new ImageCapture.Builder().build();
mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, BACK_SELECTOR, useCase);
- ImageOutputConfig config = (ImageOutputConfig) useCase.getUseCaseConfig();
+ ImageOutputConfig config = (ImageOutputConfig) useCase.getCurrentConfig();
assertThat(config.getTargetAspectRatio()).isEqualTo(AspectRatio.RATIO_4_3);
}
@@ -788,12 +788,12 @@
ImageCapture useCase = new ImageCapture.Builder().setTargetResolution(
DEFAULT_RESOLUTION).build();
- assertThat(useCase.getUseCaseConfig().containsOption(
+ assertThat(useCase.getCurrentConfig().containsOption(
ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)).isFalse();
mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, BACK_SELECTOR, useCase);
- assertThat(useCase.getUseCaseConfig().containsOption(
+ assertThat(useCase.getCurrentConfig().containsOption(
ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)).isFalse();
}
@@ -815,7 +815,7 @@
// Updates target rotation from ROTATION_0 to ROTATION_90.
imageCapture.setTargetRotation(Surface.ROTATION_90);
- ImageOutputConfig newConfig = (ImageOutputConfig) imageCapture.getUseCaseConfig();
+ ImageOutputConfig newConfig = (ImageOutputConfig) imageCapture.getCurrentConfig();
Size expectedTargetResolution = new Size(DEFAULT_RESOLUTION.getHeight(),
DEFAULT_RESOLUTION.getWidth());
@@ -1003,7 +1003,7 @@
@Test
public void useCaseConfigCanBeReset_afterUnbind() {
final ImageCapture useCase = mDefaultBuilder.build();
- UseCaseConfig<?> initialConfig = useCase.getUseCaseConfig();
+ UseCaseConfig<?> initialConfig = useCase.getCurrentConfig();
mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, BACK_SELECTOR, useCase);
@@ -1011,7 +1011,7 @@
mCamera.removeUseCases(Collections.singleton(useCase));
});
- UseCaseConfig<?> configAfterUnbinding = useCase.getUseCaseConfig();
+ UseCaseConfig<?> configAfterUnbinding = useCase.getCurrentConfig();
assertThat(initialConfig.equals(configAfterUnbinding)).isTrue();
}
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
index e0c776a..5d75838 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
@@ -357,7 +357,7 @@
public void defaultAspectRatioWillBeSet_whenTargetResolutionIsNotSet() {
Preview useCase = new Preview.Builder().build();
mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, mCameraSelector, useCase);
- ImageOutputConfig config = (ImageOutputConfig) useCase.getUseCaseConfig();
+ ImageOutputConfig config = (ImageOutputConfig) useCase.getCurrentConfig();
assertThat(config.getTargetAspectRatio()).isEqualTo(AspectRatio.RATIO_4_3);
}
@@ -366,20 +366,20 @@
assumeTrue(CameraUtil.hasCameraWithLensFacing(CameraSelector.LENS_FACING_BACK));
Preview useCase = new Preview.Builder().setTargetResolution(GUARANTEED_RESOLUTION).build();
- assertThat(useCase.getUseCaseConfig().containsOption(
+ assertThat(useCase.getCurrentConfig().containsOption(
ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)).isFalse();
mCamera = CameraUtil.createCameraAndAttachUseCase(mContext,
CameraSelector.DEFAULT_BACK_CAMERA, useCase);
- assertThat(useCase.getUseCaseConfig().containsOption(
+ assertThat(useCase.getCurrentConfig().containsOption(
ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)).isFalse();
}
@Test
public void useCaseConfigCanBeReset_afterUnbind() {
final Preview preview = mDefaultBuilder.build();
- UseCaseConfig<?> initialConfig = preview.getUseCaseConfig();
+ UseCaseConfig<?> initialConfig = preview.getCurrentConfig();
mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, mCameraSelector, preview);
@@ -387,7 +387,7 @@
mCamera.removeUseCases(Collections.singleton(preview));
});
- UseCaseConfig<?> configAfterUnbinding = preview.getUseCaseConfig();
+ UseCaseConfig<?> configAfterUnbinding = preview.getCurrentConfig();
assertThat(initialConfig.equals(configAfterUnbinding)).isTrue();
}
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplTest.java
index 749e9ed..b7b4f65 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplTest.java
@@ -41,7 +41,6 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.Manifest;
import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Rect;
@@ -79,7 +78,6 @@
import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.GrantPermissionRule;
import com.google.common.util.concurrent.ListenableFuture;
@@ -88,6 +86,7 @@
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
@@ -104,8 +103,7 @@
@RunWith(AndroidJUnit4.class)
public final class Camera2CameraControlImplTest {
@Rule
- public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(
- Manifest.permission.CAMERA);
+ public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
private Camera2CameraControlImpl mCamera2CameraControlImpl;
private CameraControlInternal.ControlUpdateCallback mControlUpdateCallback;
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
index 13e82f2..39717f0 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
@@ -59,6 +59,8 @@
import androidx.camera.core.impl.ImmediateSurface;
import androidx.camera.core.impl.Observable;
import androidx.camera.core.impl.SessionConfig;
+import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.testing.CameraUtil;
import androidx.camera.testing.HandlerUtil;
@@ -766,7 +768,7 @@
@NonNull ImageReader.OnImageAvailableListener listener) {
super(config);
// Ensure we're using the combined configuration (user config + defaults)
- mConfig = (FakeUseCaseConfig) getUseCaseConfig();
+ mConfig = (FakeUseCaseConfig) getCurrentConfig();
mImageAvailableListener = listener;
mHandlerThread.start();
@@ -776,7 +778,15 @@
cameraSelector.getLensFacing();
mCameraId = CameraUtil.getCameraIdWithLensFacing(lensFacing);
onAttach(new FakeCamera(mCameraId, null,
- new FakeCameraInfoInternal(mCameraId, 0, lensFacing)));
+ new FakeCameraInfoInternal(mCameraId, 0, lensFacing)),
+ new UseCaseConfigFactory() {
+ @Nullable
+ @Override
+ public <C extends UseCaseConfig<?>> C getConfig(
+ @NonNull Class<C> configType) {
+ return null;
+ }
+ });
updateSuggestedResolution(new Size(640, 480));
}
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ExposureDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ExposureDeviceTest.java
index 32ee4fd..3fc83e4 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ExposureDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ExposureDeviceTest.java
@@ -61,6 +61,7 @@
import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
import androidx.camera.testing.fakes.FakeUseCase;
import androidx.camera.testing.fakes.FakeUseCaseConfig;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
import androidx.core.os.HandlerCompat;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -103,7 +104,7 @@
@Rule
public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
- private ArrayList<FakeTestUseCase> mFakeTestUseCases = new ArrayList<>();
+ private final ArrayList<FakeTestUseCase> mFakeTestUseCases = new ArrayList<>();
private Camera2CameraImpl mCamera2CameraImpl;
private static ExecutorService sCameraExecutor;
private static HandlerThread sCameraHandlerThread;
@@ -158,7 +159,7 @@
mCameraUseCaseAdapter = new CameraUseCaseAdapter(mCamera2CameraImpl,
new LinkedHashSet<>(Collections.singleton(mCamera2CameraImpl)),
- fakeCameraDeviceSurfaceManager);
+ fakeCameraDeviceSurfaceManager, new FakeUseCaseConfigFactory());
}
@After
@@ -459,7 +460,7 @@
public static class FakeTestUseCase extends FakeUseCase {
private DeferrableSurface mDeferrableSurface;
- private CameraCaptureSession.StateCallback mSessionStateCallback;
+ private final CameraCaptureSession.StateCallback mSessionStateCallback;
CameraCaptureSession.CaptureCallback mCameraCaptureCallback;
FakeTestUseCase(
@@ -493,7 +494,7 @@
}
private void createPipeline(Size resolution) {
- SessionConfig.Builder builder = SessionConfig.Builder.createFrom(getUseCaseConfig());
+ SessionConfig.Builder builder = SessionConfig.Builder.createFrom(getCurrentConfig());
builder.setTemplateType(CameraDevice.TEMPLATE_PREVIEW);
if (mDeferrableSurface != null) {
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/TorchControlDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/TorchControlDeviceTest.java
index fe8afe9..eeac253 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/TorchControlDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/TorchControlDeviceTest.java
@@ -33,7 +33,6 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.GrantPermissionRule;
import com.google.common.util.concurrent.ListenableFuture;
@@ -41,6 +40,7 @@
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import java.util.concurrent.ExecutionException;
@@ -54,8 +54,7 @@
private static final int LENS_FACING = CameraSelector.LENS_FACING_BACK;
@Rule
- public GrantPermissionRule mCameraPermissionRule =
- GrantPermissionRule.grant(android.Manifest.permission.CAMERA);
+ public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
private TorchControl mTorchControl;
private CameraUseCaseAdapter mCamera;
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatDeviceTest.java
index bc553f9..4bdb7d5 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatDeviceTest.java
@@ -21,7 +21,6 @@
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
-import android.Manifest;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
@@ -38,17 +37,18 @@
import androidx.annotation.NonNull;
import androidx.camera.camera2.internal.compat.params.OutputConfigurationCompat;
import androidx.camera.camera2.internal.compat.params.SessionConfigurationCompat;
+import androidx.camera.testing.CameraUtil;
import androidx.core.os.HandlerCompat;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
-import androidx.test.rule.GrantPermissionRule;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import java.util.Collections;
@@ -67,8 +67,7 @@
private final Semaphore mOpenCloseSemaphore = new Semaphore(0);
@Rule
- public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(
- Manifest.permission.CAMERA);
+ public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
private CameraDevice mCameraDevice;
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/util/FakeRepeatingUseCase.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/util/FakeRepeatingUseCase.java
deleted file mode 100644
index b91a252..0000000
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/util/FakeRepeatingUseCase.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2019 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 androidx.camera.camera2.internal.util;
-
-import android.graphics.ImageFormat;
-import android.hardware.camera2.CameraDevice;
-import android.media.Image;
-import android.media.ImageReader;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Size;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.RestrictTo.Scope;
-import androidx.camera.core.impl.DeferrableSurface;
-import androidx.camera.core.impl.ImmediateSurface;
-import androidx.camera.core.impl.SessionConfig;
-import androidx.camera.core.impl.UseCaseConfig;
-import androidx.camera.core.impl.utils.executor.CameraXExecutors;
-import androidx.camera.testing.fakes.FakeUseCase;
-import androidx.camera.testing.fakes.FakeUseCaseConfig;
-
-/**
- * A fake {@link FakeUseCase} which contain a repeating surface.
- *
- * @hide
- */
-@RestrictTo(Scope.LIBRARY)
-public class FakeRepeatingUseCase extends FakeUseCase {
-
- private DeferrableSurface mDeferrableSurface;
-
- public FakeRepeatingUseCase(@NonNull FakeUseCaseConfig configuration) {
- super(configuration);
- }
-
- @Override
- public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
- return new FakeUseCaseConfig.Builder()
- .setSessionOptionUnpacker(
- (useCaseConfig, sessionConfigBuilder) -> {
- // Set the template since it is currently required by implementation
- sessionConfigBuilder.setTemplateType(CameraDevice.TEMPLATE_PREVIEW);
- });
- }
-
- @Override
- public void onDetached() {
- super.onDetached();
- if (mDeferrableSurface != null) {
- mDeferrableSurface.close();
- }
- mDeferrableSurface = null;
- }
-
- @Override
- @NonNull
- protected Size onSuggestedResolutionUpdated(@NonNull Size suggestedResolution) {
- FakeUseCaseConfig configWithDefaults = (FakeUseCaseConfig) getUseCaseConfig();
-
- ImageReader imageReader = ImageReader.newInstance(640, 480, ImageFormat.YUV_420_888, 2);
-
- imageReader.setOnImageAvailableListener(
- reader -> {
- Image image = reader.acquireLatestImage();
- if (image != null) {
- image.close();
- }
- },
- new Handler(Looper.getMainLooper()));
-
- SessionConfig.Builder builder = SessionConfig.Builder.createFrom(configWithDefaults);
- if (mDeferrableSurface != null) {
- mDeferrableSurface.close();
- }
- mDeferrableSurface = new ImmediateSurface(imageReader.getSurface());
- mDeferrableSurface.getTerminationFuture().addListener(imageReader::close,
- CameraXExecutors.mainThreadExecutor());
- builder.addSurface(mDeferrableSurface);
-
- updateSessionConfig(builder.build());
- notifyActive();
-
- return new Size(640, 480);
- }
-}
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2InteropDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2InteropDeviceTest.java
index c34f231..58eb8d2 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2InteropDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2InteropDeviceTest.java
@@ -24,7 +24,6 @@
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
-import android.Manifest;
import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Rect;
@@ -49,12 +48,12 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.GrantPermissionRule;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -76,8 +75,7 @@
private CameraUseCaseAdapter mCamera;
@Rule
- public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(
- Manifest.permission.CAMERA);
+ public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
@Before
public void setUp() {
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/PreviewConfigProvider.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/PreviewConfigProvider.java
index e7146ef..4025db2 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/PreviewConfigProvider.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/PreviewConfigProvider.java
@@ -59,6 +59,8 @@
captureBuilder.setTemplateType(CameraDevice.TEMPLATE_PREVIEW);
builder.setDefaultCaptureConfig(captureBuilder.build());
builder.setCaptureOptionUnpacker(Camera2CaptureOptionUnpacker.INSTANCE);
+
+ builder.setMaxResolution(SupportedSurfaceCombination.getPreviewSize(mWindowManager));
builder.setTargetAspectRatio(AspectRatio.RATIO_4_3);
// TODO(b/160477756): Make UseCase default config providers only provider static configs
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
index 47ebf56..b16f526 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
@@ -1148,7 +1148,8 @@
* (1920x1080), whichever is smaller.
*/
@SuppressWarnings("deprecation") /* defaultDisplay */
- private Size getPreviewSize(WindowManager windowManager) {
+ @NonNull
+ public static Size getPreviewSize(@NonNull WindowManager windowManager) {
Point displaySize = new Point();
windowManager.getDefaultDisplay().getRealSize(displaySize);
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManagerTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManagerTest.java
index 08a4c7b..5c6d82e 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManagerTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManagerTest.java
@@ -134,6 +134,7 @@
private final Context mContext = ApplicationProvider.getApplicationContext();
private CameraDeviceSurfaceManager mSurfaceManager;
+ private UseCaseConfigFactory mUseCaseConfigFactory;
private FakeCameraFactory mCameraFactory;
@Before
@@ -352,7 +353,8 @@
useCases.add(preview);
Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
- Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+ Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+ mUseCaseConfigFactory);
// A legacy level camera device can't support JPEG (ImageCapture) + PRIV (VideoCapture) +
// PRIV (Preview) combination. An IllegalArgumentException will be thrown when trying to
// bind these use cases at the same time.
@@ -378,7 +380,8 @@
useCases.add(preview);
Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
- Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+ Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+ mUseCaseConfigFactory);
Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
mSurfaceManager.getSuggestedResolutions(LIMITED_CAMERA_ID, Collections.emptyList(),
new ArrayList<>(useCaseToConfigMap.values()));
@@ -573,7 +576,14 @@
private void initCameraX() {
CameraXConfig cameraXConfig = createFakeAppConfig();
CameraX.initialize(mContext, cameraXConfig);
- mSurfaceManager = CameraX.getSurfaceManager();
+ CameraX cameraX;
+ try {
+ cameraX = CameraX.getOrCreateInstance(mContext).get();
+ } catch (ExecutionException | InterruptedException e) {
+ throw new IllegalStateException("Unable to initialize CameraX for test.");
+ }
+ mSurfaceManager = cameraX.getCameraDeviceSurfaceManager();
+ mUseCaseConfigFactory = cameraX.getDefaultConfigFactory();
}
private CameraXConfig createFakeAppConfig() {
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSizeConstraintsTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSizeConstraintsTest.java
index 8cd2ef8..e7a338b 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSizeConstraintsTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSizeConstraintsTest.java
@@ -147,7 +147,7 @@
FakeUseCase useCase = new FakeUseCaseConfig.Builder().setBufferFormat(
ImageFormat.JPEG).build();
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
for (Size size : excludedSizes) {
assertThat(resultList.contains(size)).isFalse();
@@ -178,7 +178,7 @@
FakeUseCase useCase = new FakeUseCaseConfig.Builder().setBufferFormat(
ImageFormat.JPEG).build();
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
for (Size size : excludedSizes) {
assertThat(resultList.contains(size)).isFalse();
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java
index a71184d..7896141 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java
@@ -54,6 +54,7 @@
import androidx.camera.core.impl.SurfaceConfig.ConfigSize;
import androidx.camera.core.impl.SurfaceConfig.ConfigType;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.internal.CameraUseCaseAdapter;
import androidx.camera.testing.CameraUtil;
@@ -154,6 +155,7 @@
private final Context mContext = RuntimeEnvironment.application.getApplicationContext();
private FakeCameraFactory mCameraFactory;
+ private UseCaseConfigFactory mUseCaseConfigFactory;
@Before
@SuppressWarnings("deprecation") /* defaultDisplay */
@@ -491,7 +493,8 @@
List<UseCase> useCases = new ArrayList<>();
useCases.add(fakeUseCase);
Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
- Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+ Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+ mUseCaseConfigFactory);
Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
new ArrayList<>(useCaseToConfigMap.values()));
@@ -600,7 +603,8 @@
useCases.add(imageCapture);
useCases.add(imageAnalysis);
Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
- Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+ Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+ mUseCaseConfigFactory);
Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
new ArrayList<>(useCaseToConfigMap.values()));
@@ -647,7 +651,8 @@
List<UseCase> useCases = new ArrayList<>();
useCases.add(preview);
Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
- Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+ Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+ mUseCaseConfigFactory);
Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
new ArrayList<>(useCaseToConfigMap.values()));
@@ -683,10 +688,10 @@
Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
- Collections.singletonList(imageCapture.getUseCaseConfig()));
+ Collections.singletonList(imageCapture.getCurrentConfig()));
assertThat(targetResolution).isEqualTo(
- suggestedResolutionMap.get(imageCapture.getUseCaseConfig()));
+ suggestedResolutionMap.get(imageCapture.getCurrentConfig()));
}
}
@@ -707,10 +712,10 @@
Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
- Arrays.asList(imageCapture.getUseCaseConfig()));
+ Arrays.asList(imageCapture.getCurrentConfig()));
assertThat(new Size(1280, 720)).isEqualTo(
- suggestedResolutionMap.get(imageCapture.getUseCaseConfig()));
+ suggestedResolutionMap.get(imageCapture.getCurrentConfig()));
}
@@ -736,7 +741,8 @@
useCases.add(videoCapture);
useCases.add(preview);
Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
- Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+ Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+ mUseCaseConfigFactory);
Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
new ArrayList<>(useCaseToConfigMap.values()));
@@ -767,7 +773,8 @@
useCases.add(preview);
Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
- Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+ Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+ mUseCaseConfigFactory);
Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
new ArrayList<>(useCaseToConfigMap.values()));
@@ -809,7 +816,8 @@
useCases.add(preview);
useCases.add(imageAnalysis);
Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
- Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+ Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+ mUseCaseConfigFactory);
Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
new ArrayList<>(useCaseToConfigMap.values()));
@@ -843,7 +851,8 @@
useCases.add(preview);
useCases.add(imageAnalysis);
Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
- Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+ Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+ mUseCaseConfigFactory);
Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
new ArrayList<>(useCaseToConfigMap.values()));
@@ -924,7 +933,8 @@
useCases.add(videoCapture);
useCases.add(preview);
Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
- Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+ Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+ mUseCaseConfigFactory);
Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
new ArrayList<>(useCaseToConfigMap.values()));
@@ -1104,7 +1114,8 @@
useCases.add(imageCapture);
Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
- Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+ Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+ mUseCaseConfigFactory);
Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
new ArrayList<>(useCaseToConfigMap.values()));
@@ -1147,7 +1158,7 @@
// removed. No any aspect ratio related setting. The returned sizes list will be sorted in
// descending order.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
new Size(4032, 3024),
new Size(3840, 2160),
@@ -1176,7 +1187,7 @@
// list is sorted in descending order. Other items will be put in the following that are
// sorted by aspect ratio delta and then area size.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Matched AspectRatio items, sorted by area size.
new Size(4032, 3024),
@@ -1209,7 +1220,7 @@
// list is sorted in descending order. Other items will be put in the following that are
// sorted by aspect ratio delta and then area size.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Matched AspectRatio items, sorted by area size.
new Size(3840, 2160),
@@ -1239,7 +1250,7 @@
AspectRatio.RATIO_16_9).build();
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList;
// There is default minimum size 640x480 setting. Sizes smaller than 640x480 will be
// removed.
@@ -1304,7 +1315,7 @@
// order. Other items will be put in the following that are sorted by aspect ratio delta
// and then area size.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Matched AspectRatio items, sorted by area size.
new Size(1920, 1080),
@@ -1333,7 +1344,7 @@
// Unnecessary big enough sizes will be removed from the result list. There is default
// minimum size 640x480 setting. Sizes smaller than 640x480 will also be removed.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList;
if (Build.VERSION.SDK_INT == 21) {
// Sizes with the same aspect ratio as maximum JPEG resolution will be in front of
@@ -1395,7 +1406,7 @@
// items will be put in the following that are sorted by aspect ratio delta and then area
// size.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Matched AspectRatio items, sorted by area size.
new Size(1280, 960),
@@ -1428,7 +1439,7 @@
// order. Other items will be put in the following that are sorted by aspect ratio delta
// and then area size.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Matched AspectRatio items, sorted by area size.
new Size(320, 240),
@@ -1456,7 +1467,7 @@
// therefore, sizes of aspect ratio 4/3 will be in front of the returned sizes list and
// the list is sorted in descending order.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Sizes of 4/3 are near to aspect ratio of 1800/1440
new Size(1920, 1440),
@@ -1490,7 +1501,7 @@
// therefore, sizes of aspect ratio 16/9 will be in front of the returned sizes list and
// the list is sorted in descending order.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Sizes of 16/9 are near to aspect ratio of 1280/600
new Size(1280, 720),
@@ -1517,7 +1528,7 @@
// larger than 1280x720 will be removed. The returned sizes list will be sorted in
// descending order.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
new Size(1280, 720),
new Size(960, 544),
@@ -1542,7 +1553,7 @@
// resolution as 1280x720. Unnecessary big enough sizes will also be removed. The
// returned sizes list will be sorted in descending order.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
new Size(1280, 720),
new Size(960, 544),
@@ -1570,7 +1581,7 @@
// in descending order. Other items will be put in the following that are sorted by
// aspect ratio delta and then area size.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Matched AspectRatio items, sorted by area size.
new Size(1920, 1080),
@@ -1605,7 +1616,7 @@
// removed. There is target resolution 1920x1080 (16:9). Even 640x480 does not match 16:9
// requirement, it will still be returned to use.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
new Size(640, 480)
});
@@ -1632,7 +1643,7 @@
// bound and it is also smaller than 640x480, the default minimum size bound will be
// ignored. Then, sizes equal to or smaller than 320x240 will be kept in the result list.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
new Size(320, 240),
new Size(320, 180),
@@ -1663,7 +1674,7 @@
// size bound will be ignored. Then, sizes equal to or smaller than 320x180 will be kept
// in the result list.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
new Size(320, 180),
new Size(256, 144)
@@ -1693,7 +1704,7 @@
// size bound will be ignored. Then, all sizes equal to or smaller than 320x320 will be
// kept in the result list.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
new Size(320, 180),
new Size(256, 144),
@@ -1721,7 +1732,7 @@
// order. Other items will be put in the following that are sorted by aspect ratio delta
// and then area size.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Matched AspectRatio items, sorted by area size.
new Size(1920, 1080),
@@ -1758,7 +1769,7 @@
// smaller than 640x480, the default minimum size bound will be ignored. Then, sizes
// equal to or smaller than 320x200 will be kept in the result list.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
new Size(320, 180),
new Size(256, 144)
@@ -1786,7 +1797,7 @@
// filtered out by it. The result list will only keep one big enough size of aspect ratio
// 4:3 and 16:9.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
new Size(320, 240),
new Size(256, 144)
@@ -1811,7 +1822,7 @@
// All sizes will be filtered out by the max resolution 192x144 setting and an
// IllegalArgumentException will be thrown.
- supportedSurfaceCombination.getSupportedOutputSizes(useCase.getUseCaseConfig());
+ supportedSurfaceCombination.getSupportedOutputSizes(useCase.getCurrentConfig());
}
@Test
@@ -1836,7 +1847,7 @@
// result list. After ignoring mod 16 calculation for small sizes, 256x144 will still be
// kept as a 16:9 resolution as the result.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
new Size(296, 144),
new Size(256, 144),
@@ -1866,14 +1877,8 @@
FakeUseCase useCase = new FakeUseCaseConfig.Builder().setTargetResolution(
new Size(1080, 2016)).build();
- Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
- Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(Arrays.asList(useCase));
- Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
- supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
- new ArrayList<>(useCaseToConfigMap.values()));
-
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
new Size(1920, 1080),
new Size(1280, 720),
@@ -1916,7 +1921,7 @@
// items will be put in the following that are sorted by aspect ratio delta and then area
// size.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Matched AspectRatio items, sorted by area size.
new Size(1080, 1920),
@@ -1962,7 +1967,7 @@
// items will be put in the following that are sorted by aspect ratio delta and then area
// size.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Matched AspectRatio items, sorted by area size.
new Size(1080, 1920),
@@ -1994,7 +1999,7 @@
// list is sorted in descending order. Other items will be put in the following that are
// sorted by aspect ratio delta and then area size.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Matched AspectRatio items, sorted by area size.
new Size(3840, 2160),
@@ -2038,7 +2043,7 @@
// list is sorted in descending order. Other items will be put in the following that are
// sorted by aspect ratio delta and then area size.
List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
- useCase.getUseCaseConfig());
+ useCase.getCurrentConfig());
List<Size> expectedList = Arrays.asList(new Size[]{
// Matched AspectRatio items, sorted by area size.
new Size(1920, 1080),
@@ -2132,6 +2137,13 @@
.setCameraFactoryProvider((ignored0, ignored1) -> mCameraFactory)
.build();
CameraX.initialize(mContext, cameraXConfig);
+ CameraX cameraX;
+ try {
+ cameraX = CameraX.getOrCreateInstance(mContext).get();
+ } catch (ExecutionException | InterruptedException e) {
+ throw new IllegalStateException("Unable to initialize CameraX for test.");
+ }
+ mUseCaseConfigFactory = cameraX.getDefaultConfigFactory();
}
private boolean isRawSupported(int[] capabilities) {
diff --git a/camera/camera-core/api/1.0.0-beta10.txt b/camera/camera-core/api/1.0.0-beta10.txt
new file mode 100644
index 0000000..0a36e63
--- /dev/null
+++ b/camera/camera-core/api/1.0.0-beta10.txt
@@ -0,0 +1,306 @@
+// Signature format: 3.0
+package androidx.camera.core {
+
+ public class AspectRatio {
+ field public static final int RATIO_16_9 = 1; // 0x1
+ field public static final int RATIO_4_3 = 0; // 0x0
+ }
+
+ public interface Camera {
+ method public androidx.camera.core.CameraControl getCameraControl();
+ method public androidx.camera.core.CameraInfo getCameraInfo();
+ }
+
+ public interface CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+ }
+
+ public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+ }
+
+ public interface CameraInfo {
+ method public int getSensorRotationDegrees();
+ method public int getSensorRotationDegrees(int);
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
+ method public boolean hasFlashUnit();
+ }
+
+ public final class CameraInfoUnavailableException extends java.lang.Exception {
+ }
+
+ public final class CameraSelector {
+ field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+ field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+ field public static final int LENS_FACING_BACK = 1; // 0x1
+ field public static final int LENS_FACING_FRONT = 0; // 0x0
+ }
+
+ public static final class CameraSelector.Builder {
+ ctor public CameraSelector.Builder();
+ method public androidx.camera.core.CameraSelector build();
+ method public androidx.camera.core.CameraSelector.Builder requireLensFacing(int);
+ }
+
+ public class CameraUnavailableException extends java.lang.Exception {
+ ctor public CameraUnavailableException(int);
+ ctor public CameraUnavailableException(int, String?);
+ ctor public CameraUnavailableException(int, String?, Throwable?);
+ ctor public CameraUnavailableException(int, Throwable?);
+ method public int getReason();
+ field public static final int CAMERA_DISABLED = 1; // 0x1
+ field public static final int CAMERA_DISCONNECTED = 2; // 0x2
+ field public static final int CAMERA_ERROR = 3; // 0x3
+ field public static final int CAMERA_IN_USE = 4; // 0x4
+ field public static final int CAMERA_MAX_IN_USE = 5; // 0x5
+ field public static final int CAMERA_UNAVAILABLE_DO_NOT_DISTURB = 6; // 0x6
+ field public static final int CAMERA_UNKNOWN_ERROR = 0; // 0x0
+ }
+
+ public final class CameraXConfig {
+ }
+
+ public static final class CameraXConfig.Builder {
+ method public androidx.camera.core.CameraXConfig build();
+ method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+ method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+ }
+
+ public static interface CameraXConfig.Provider {
+ method public androidx.camera.core.CameraXConfig getCameraXConfig();
+ }
+
+ public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraInfo, float, float);
+ }
+
+ public interface ExtendableBuilder<T> {
+ method public T build();
+ }
+
+ public final class FocusMeteringAction {
+ method public long getAutoCancelDurationInMillis();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+ method public boolean isAutoCancelEnabled();
+ field public static final int FLAG_AE = 2; // 0x2
+ field public static final int FLAG_AF = 1; // 0x1
+ field public static final int FLAG_AWB = 4; // 0x4
+ }
+
+ public static class FocusMeteringAction.Builder {
+ ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint);
+ ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction build();
+ method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+ method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+ }
+
+ public final class FocusMeteringResult {
+ method public boolean isFocusSuccessful();
+ }
+
+ public final class ImageAnalysis extends androidx.camera.core.UseCase {
+ method public void clearAnalyzer();
+ method public int getBackpressureStrategy();
+ method public int getImageQueueDepth();
+ method public int getTargetRotation();
+ method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method public void setTargetRotation(int);
+ field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+ field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+ }
+
+ public static interface ImageAnalysis.Analyzer {
+ method public void analyze(androidx.camera.core.ImageProxy);
+ }
+
+ public static final class ImageAnalysis.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageAnalysis> {
+ ctor public ImageAnalysis.Builder();
+ method public androidx.camera.core.ImageAnalysis build();
+ method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+ }
+
+ public final class ImageCapture extends androidx.camera.core.UseCase {
+ method public int getCaptureMode();
+ method public int getFlashMode();
+ method public int getTargetRotation();
+ method public void setCropAspectRatio(android.util.Rational);
+ method public void setFlashMode(int);
+ method public void setTargetRotation(int);
+ method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ method public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+ field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+ field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+ field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+ field public static final int ERROR_FILE_IO = 1; // 0x1
+ field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int FLASH_MODE_AUTO = 0; // 0x0
+ field public static final int FLASH_MODE_OFF = 2; // 0x2
+ field public static final int FLASH_MODE_ON = 1; // 0x1
+ }
+
+ public static final class ImageCapture.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageCapture> {
+ ctor public ImageCapture.Builder();
+ method public androidx.camera.core.ImageCapture build();
+ method public androidx.camera.core.ImageCapture.Builder setCaptureMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+ method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+ }
+
+ public static final class ImageCapture.Metadata {
+ ctor public ImageCapture.Metadata();
+ method public android.location.Location? getLocation();
+ method public boolean isReversedHorizontal();
+ method public boolean isReversedVertical();
+ method public void setLocation(android.location.Location?);
+ method public void setReversedHorizontal(boolean);
+ method public void setReversedVertical(boolean);
+ }
+
+ public abstract static class ImageCapture.OnImageCapturedCallback {
+ ctor public ImageCapture.OnImageCapturedCallback();
+ method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+ method public void onError(androidx.camera.core.ImageCaptureException);
+ }
+
+ public static interface ImageCapture.OnImageSavedCallback {
+ method public void onError(androidx.camera.core.ImageCaptureException);
+ method public void onImageSaved(androidx.camera.core.ImageCapture.OutputFileResults);
+ }
+
+ public static final class ImageCapture.OutputFileOptions {
+ }
+
+ public static final class ImageCapture.OutputFileOptions.Builder {
+ ctor public ImageCapture.OutputFileOptions.Builder(java.io.File);
+ ctor public ImageCapture.OutputFileOptions.Builder(android.content.ContentResolver, android.net.Uri, android.content.ContentValues);
+ ctor public ImageCapture.OutputFileOptions.Builder(java.io.OutputStream);
+ method public androidx.camera.core.ImageCapture.OutputFileOptions build();
+ method public androidx.camera.core.ImageCapture.OutputFileOptions.Builder setMetadata(androidx.camera.core.ImageCapture.Metadata);
+ }
+
+ public static class ImageCapture.OutputFileResults {
+ method public android.net.Uri? getSavedUri();
+ }
+
+ public class ImageCaptureException extends java.lang.Exception {
+ ctor public ImageCaptureException(int, String, Throwable?);
+ method public int getImageCaptureError();
+ }
+
+ public interface ImageInfo {
+ method public int getRotationDegrees();
+ method public long getTimestamp();
+ }
+
+ public interface ImageProxy extends java.lang.AutoCloseable {
+ method public void close();
+ method public android.graphics.Rect getCropRect();
+ method public int getFormat();
+ method public int getHeight();
+ method public androidx.camera.core.ImageInfo getImageInfo();
+ method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+ method public int getWidth();
+ method public void setCropRect(android.graphics.Rect?);
+ }
+
+ public static interface ImageProxy.PlaneProxy {
+ method public java.nio.ByteBuffer getBuffer();
+ method public int getPixelStride();
+ method public int getRowStride();
+ }
+
+ public class InitializationException extends java.lang.Exception {
+ ctor public InitializationException(String?);
+ ctor public InitializationException(String?, Throwable?);
+ ctor public InitializationException(Throwable?);
+ }
+
+ public class MeteringPoint {
+ method public float getSize();
+ }
+
+ public abstract class MeteringPointFactory {
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+ method public static float getDefaultPointSize();
+ }
+
+ public final class Preview extends androidx.camera.core.UseCase {
+ method public int getTargetRotation();
+ method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
+ method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
+ }
+
+ public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
+ ctor public Preview.Builder();
+ method public androidx.camera.core.Preview build();
+ method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.Preview.Builder setTargetName(String);
+ method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+ }
+
+ public static interface Preview.SurfaceProvider {
+ method public void onSurfaceRequested(androidx.camera.core.SurfaceRequest);
+ }
+
+ public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public SurfaceOrientedMeteringPointFactory(float, float);
+ ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+ }
+
+ public final class SurfaceRequest {
+ method public void addRequestCancellationListener(java.util.concurrent.Executor, Runnable);
+ method public android.util.Size getResolution();
+ method public void provideSurface(android.view.Surface, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceRequest.Result!>);
+ method public boolean willNotProvideSurface();
+ }
+
+ @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.Result {
+ method public abstract int getResultCode();
+ method public abstract android.view.Surface getSurface();
+ field public static final int RESULT_INVALID_SURFACE = 2; // 0x2
+ field public static final int RESULT_REQUEST_CANCELLED = 1; // 0x1
+ field public static final int RESULT_SURFACE_ALREADY_PROVIDED = 3; // 0x3
+ field public static final int RESULT_SURFACE_USED_SUCCESSFULLY = 0; // 0x0
+ field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
+ }
+
+ public class TorchState {
+ field public static final int OFF = 0; // 0x0
+ field public static final int ON = 1; // 0x1
+ }
+
+ public abstract class UseCase {
+ }
+
+ public interface ZoomState {
+ method public float getLinearZoom();
+ method public float getMaxZoomRatio();
+ method public float getMinZoomRatio();
+ method public float getZoomRatio();
+ }
+
+}
+
diff --git a/camera/camera-core/api/public_plus_experimental_1.0.0-beta10.txt b/camera/camera-core/api/public_plus_experimental_1.0.0-beta10.txt
new file mode 100644
index 0000000..7da2353
--- /dev/null
+++ b/camera/camera-core/api/public_plus_experimental_1.0.0-beta10.txt
@@ -0,0 +1,376 @@
+// Signature format: 3.0
+package androidx.camera.core {
+
+ public class AspectRatio {
+ field public static final int RATIO_16_9 = 1; // 0x1
+ field public static final int RATIO_4_3 = 0; // 0x0
+ }
+
+ public interface Camera {
+ method public androidx.camera.core.CameraControl getCameraControl();
+ method public androidx.camera.core.CameraInfo getCameraInfo();
+ }
+
+ public interface CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method @androidx.camera.core.ExperimentalExposureCompensation public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> setExposureCompensationIndex(int);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+ }
+
+ public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+ }
+
+ @androidx.camera.core.ExperimentalCameraFilter public interface CameraFilter {
+ method public java.util.LinkedHashSet<androidx.camera.core.Camera!> filter(java.util.LinkedHashSet<androidx.camera.core.Camera!>);
+ }
+
+ public interface CameraInfo {
+ method @androidx.camera.core.ExperimentalExposureCompensation public androidx.camera.core.ExposureState getExposureState();
+ method public int getSensorRotationDegrees();
+ method public int getSensorRotationDegrees(int);
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
+ method public boolean hasFlashUnit();
+ }
+
+ public final class CameraInfoUnavailableException extends java.lang.Exception {
+ }
+
+ public final class CameraSelector {
+ field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+ field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+ field public static final int LENS_FACING_BACK = 1; // 0x1
+ field public static final int LENS_FACING_FRONT = 0; // 0x0
+ }
+
+ public static final class CameraSelector.Builder {
+ ctor public CameraSelector.Builder();
+ method @androidx.camera.core.ExperimentalCameraFilter public androidx.camera.core.CameraSelector.Builder addCameraFilter(androidx.camera.core.CameraFilter);
+ method public androidx.camera.core.CameraSelector build();
+ method public androidx.camera.core.CameraSelector.Builder requireLensFacing(int);
+ }
+
+ public class CameraUnavailableException extends java.lang.Exception {
+ ctor public CameraUnavailableException(int);
+ ctor public CameraUnavailableException(int, String?);
+ ctor public CameraUnavailableException(int, String?, Throwable?);
+ ctor public CameraUnavailableException(int, Throwable?);
+ method public int getReason();
+ field public static final int CAMERA_DISABLED = 1; // 0x1
+ field public static final int CAMERA_DISCONNECTED = 2; // 0x2
+ field public static final int CAMERA_ERROR = 3; // 0x3
+ field public static final int CAMERA_IN_USE = 4; // 0x4
+ field public static final int CAMERA_MAX_IN_USE = 5; // 0x5
+ field public static final int CAMERA_UNAVAILABLE_DO_NOT_DISTURB = 6; // 0x6
+ field public static final int CAMERA_UNKNOWN_ERROR = 0; // 0x0
+ }
+
+ public final class CameraXConfig {
+ }
+
+ public static final class CameraXConfig.Builder {
+ method public androidx.camera.core.CameraXConfig build();
+ method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+ method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+ method @androidx.camera.core.ExperimentalCustomizableThreads public androidx.camera.core.CameraXConfig.Builder setSchedulerHandler(android.os.Handler);
+ }
+
+ public static interface CameraXConfig.Provider {
+ method public androidx.camera.core.CameraXConfig getCameraXConfig();
+ }
+
+ public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraInfo, float, float);
+ }
+
+ @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCameraFilter {
+ }
+
+ @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCustomizableThreads {
+ }
+
+ @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalExposureCompensation {
+ }
+
+ @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalGetImage {
+ }
+
+ @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalUseCaseGroup {
+ }
+
+ @androidx.camera.core.ExperimentalExposureCompensation public interface ExposureState {
+ method public int getExposureCompensationIndex();
+ method public android.util.Range<java.lang.Integer!> getExposureCompensationRange();
+ method public android.util.Rational getExposureCompensationStep();
+ method public boolean isExposureCompensationSupported();
+ }
+
+ public interface ExtendableBuilder<T> {
+ method public T build();
+ }
+
+ public final class FocusMeteringAction {
+ method public long getAutoCancelDurationInMillis();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+ method public boolean isAutoCancelEnabled();
+ field public static final int FLAG_AE = 2; // 0x2
+ field public static final int FLAG_AF = 1; // 0x1
+ field public static final int FLAG_AWB = 4; // 0x4
+ }
+
+ public static class FocusMeteringAction.Builder {
+ ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint);
+ ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction build();
+ method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+ method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+ }
+
+ public final class FocusMeteringResult {
+ method public boolean isFocusSuccessful();
+ }
+
+ public final class ImageAnalysis extends androidx.camera.core.UseCase {
+ method public void clearAnalyzer();
+ method public int getBackpressureStrategy();
+ method public int getImageQueueDepth();
+ method public int getTargetRotation();
+ method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method public void setTargetRotation(int);
+ field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+ field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+ }
+
+ public static interface ImageAnalysis.Analyzer {
+ method public void analyze(androidx.camera.core.ImageProxy);
+ }
+
+ public static final class ImageAnalysis.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageAnalysis> {
+ ctor public ImageAnalysis.Builder();
+ method public androidx.camera.core.ImageAnalysis build();
+ method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+ }
+
+ public final class ImageCapture extends androidx.camera.core.UseCase {
+ method public int getCaptureMode();
+ method public int getFlashMode();
+ method public int getTargetRotation();
+ method public void setCropAspectRatio(android.util.Rational);
+ method public void setFlashMode(int);
+ method public void setTargetRotation(int);
+ method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ method public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+ field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+ field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+ field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+ field public static final int ERROR_FILE_IO = 1; // 0x1
+ field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int FLASH_MODE_AUTO = 0; // 0x0
+ field public static final int FLASH_MODE_OFF = 2; // 0x2
+ field public static final int FLASH_MODE_ON = 1; // 0x1
+ }
+
+ public static final class ImageCapture.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageCapture> {
+ ctor public ImageCapture.Builder();
+ method public androidx.camera.core.ImageCapture build();
+ method public androidx.camera.core.ImageCapture.Builder setCaptureMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+ method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+ }
+
+ public static final class ImageCapture.Metadata {
+ ctor public ImageCapture.Metadata();
+ method public android.location.Location? getLocation();
+ method public boolean isReversedHorizontal();
+ method public boolean isReversedVertical();
+ method public void setLocation(android.location.Location?);
+ method public void setReversedHorizontal(boolean);
+ method public void setReversedVertical(boolean);
+ }
+
+ public abstract static class ImageCapture.OnImageCapturedCallback {
+ ctor public ImageCapture.OnImageCapturedCallback();
+ method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+ method public void onError(androidx.camera.core.ImageCaptureException);
+ }
+
+ public static interface ImageCapture.OnImageSavedCallback {
+ method public void onError(androidx.camera.core.ImageCaptureException);
+ method public void onImageSaved(androidx.camera.core.ImageCapture.OutputFileResults);
+ }
+
+ public static final class ImageCapture.OutputFileOptions {
+ }
+
+ public static final class ImageCapture.OutputFileOptions.Builder {
+ ctor public ImageCapture.OutputFileOptions.Builder(java.io.File);
+ ctor public ImageCapture.OutputFileOptions.Builder(android.content.ContentResolver, android.net.Uri, android.content.ContentValues);
+ ctor public ImageCapture.OutputFileOptions.Builder(java.io.OutputStream);
+ method public androidx.camera.core.ImageCapture.OutputFileOptions build();
+ method public androidx.camera.core.ImageCapture.OutputFileOptions.Builder setMetadata(androidx.camera.core.ImageCapture.Metadata);
+ }
+
+ public static class ImageCapture.OutputFileResults {
+ method public android.net.Uri? getSavedUri();
+ }
+
+ public class ImageCaptureException extends java.lang.Exception {
+ ctor public ImageCaptureException(int, String, Throwable?);
+ method public int getImageCaptureError();
+ }
+
+ public interface ImageInfo {
+ method public int getRotationDegrees();
+ method public long getTimestamp();
+ }
+
+ public interface ImageProxy extends java.lang.AutoCloseable {
+ method public void close();
+ method public android.graphics.Rect getCropRect();
+ method public int getFormat();
+ method public int getHeight();
+ method @androidx.camera.core.ExperimentalGetImage public android.media.Image? getImage();
+ method public androidx.camera.core.ImageInfo getImageInfo();
+ method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+ method public int getWidth();
+ method public void setCropRect(android.graphics.Rect?);
+ }
+
+ public static interface ImageProxy.PlaneProxy {
+ method public java.nio.ByteBuffer getBuffer();
+ method public int getPixelStride();
+ method public int getRowStride();
+ }
+
+ public class InitializationException extends java.lang.Exception {
+ ctor public InitializationException(String?);
+ ctor public InitializationException(String?, Throwable?);
+ ctor public InitializationException(Throwable?);
+ }
+
+ public class MeteringPoint {
+ method public float getSize();
+ }
+
+ public abstract class MeteringPointFactory {
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+ method public static float getDefaultPointSize();
+ }
+
+ public final class Preview extends androidx.camera.core.UseCase {
+ method public int getTargetRotation();
+ method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
+ method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
+ method @androidx.camera.core.ExperimentalUseCaseGroup public void setTargetRotation(int);
+ }
+
+ public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
+ ctor public Preview.Builder();
+ method public androidx.camera.core.Preview build();
+ method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.Preview.Builder setTargetName(String);
+ method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+ }
+
+ public static interface Preview.SurfaceProvider {
+ method public void onSurfaceRequested(androidx.camera.core.SurfaceRequest);
+ }
+
+ public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public SurfaceOrientedMeteringPointFactory(float, float);
+ ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+ }
+
+ public final class SurfaceRequest {
+ method public void addRequestCancellationListener(java.util.concurrent.Executor, Runnable);
+ method @androidx.camera.core.ExperimentalUseCaseGroup public void clearTransformationInfoListener();
+ method public android.util.Size getResolution();
+ method public void provideSurface(android.view.Surface, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceRequest.Result!>);
+ method @androidx.camera.core.ExperimentalUseCaseGroup public void setTransformationInfoListener(java.util.concurrent.Executor, androidx.camera.core.SurfaceRequest.TransformationInfoListener);
+ method public boolean willNotProvideSurface();
+ }
+
+ @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.Result {
+ method public abstract int getResultCode();
+ method public abstract android.view.Surface getSurface();
+ field public static final int RESULT_INVALID_SURFACE = 2; // 0x2
+ field public static final int RESULT_REQUEST_CANCELLED = 1; // 0x1
+ field public static final int RESULT_SURFACE_ALREADY_PROVIDED = 3; // 0x3
+ field public static final int RESULT_SURFACE_USED_SUCCESSFULLY = 0; // 0x0
+ field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
+ }
+
+ @androidx.camera.core.ExperimentalUseCaseGroup @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.TransformationInfo {
+ method public abstract android.graphics.Rect getCropRect();
+ method public abstract int getRotationDegrees();
+ }
+
+ @androidx.camera.core.ExperimentalUseCaseGroup public static interface SurfaceRequest.TransformationInfoListener {
+ method public void onTransformationInfoUpdate(androidx.camera.core.SurfaceRequest.TransformationInfo);
+ }
+
+ public class TorchState {
+ field public static final int OFF = 0; // 0x0
+ field public static final int ON = 1; // 0x1
+ }
+
+ public abstract class UseCase {
+ }
+
+ @androidx.camera.core.ExperimentalUseCaseGroup public final class UseCaseGroup {
+ method public java.util.List<androidx.camera.core.UseCase!> getUseCases();
+ method public androidx.camera.core.ViewPort? getViewPort();
+ }
+
+ @androidx.camera.core.ExperimentalUseCaseGroup public static final class UseCaseGroup.Builder {
+ ctor public UseCaseGroup.Builder();
+ method public androidx.camera.core.UseCaseGroup.Builder addUseCase(androidx.camera.core.UseCase);
+ method public androidx.camera.core.UseCaseGroup build();
+ method public androidx.camera.core.UseCaseGroup.Builder setViewPort(androidx.camera.core.ViewPort);
+ }
+
+ @androidx.camera.core.ExperimentalUseCaseGroup public final class ViewPort {
+ method public android.util.Rational getAspectRatio();
+ method public int getRotation();
+ method public int getScaleType();
+ field public static final int FILL_CENTER = 1; // 0x1
+ field public static final int FILL_END = 2; // 0x2
+ field public static final int FILL_START = 0; // 0x0
+ field public static final int FIT = 3; // 0x3
+ }
+
+ @androidx.camera.core.ExperimentalUseCaseGroup public static final class ViewPort.Builder {
+ ctor public ViewPort.Builder(android.util.Rational, int);
+ method public androidx.camera.core.ViewPort build();
+ }
+
+ public interface ZoomState {
+ method public float getLinearZoom();
+ method public float getMaxZoomRatio();
+ method public float getMinZoomRatio();
+ method public float getZoomRatio();
+ }
+
+}
+
diff --git a/camera/camera-core/api/res-1.0.0-beta10.txt b/camera/camera-core/api/res-1.0.0-beta10.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-core/api/res-1.0.0-beta10.txt
diff --git a/camera/camera-core/api/restricted_1.0.0-beta10.txt b/camera/camera-core/api/restricted_1.0.0-beta10.txt
new file mode 100644
index 0000000..0a36e63
--- /dev/null
+++ b/camera/camera-core/api/restricted_1.0.0-beta10.txt
@@ -0,0 +1,306 @@
+// Signature format: 3.0
+package androidx.camera.core {
+
+ public class AspectRatio {
+ field public static final int RATIO_16_9 = 1; // 0x1
+ field public static final int RATIO_4_3 = 0; // 0x0
+ }
+
+ public interface Camera {
+ method public androidx.camera.core.CameraControl getCameraControl();
+ method public androidx.camera.core.CameraInfo getCameraInfo();
+ }
+
+ public interface CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+ }
+
+ public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+ }
+
+ public interface CameraInfo {
+ method public int getSensorRotationDegrees();
+ method public int getSensorRotationDegrees(int);
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
+ method public boolean hasFlashUnit();
+ }
+
+ public final class CameraInfoUnavailableException extends java.lang.Exception {
+ }
+
+ public final class CameraSelector {
+ field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+ field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+ field public static final int LENS_FACING_BACK = 1; // 0x1
+ field public static final int LENS_FACING_FRONT = 0; // 0x0
+ }
+
+ public static final class CameraSelector.Builder {
+ ctor public CameraSelector.Builder();
+ method public androidx.camera.core.CameraSelector build();
+ method public androidx.camera.core.CameraSelector.Builder requireLensFacing(int);
+ }
+
+ public class CameraUnavailableException extends java.lang.Exception {
+ ctor public CameraUnavailableException(int);
+ ctor public CameraUnavailableException(int, String?);
+ ctor public CameraUnavailableException(int, String?, Throwable?);
+ ctor public CameraUnavailableException(int, Throwable?);
+ method public int getReason();
+ field public static final int CAMERA_DISABLED = 1; // 0x1
+ field public static final int CAMERA_DISCONNECTED = 2; // 0x2
+ field public static final int CAMERA_ERROR = 3; // 0x3
+ field public static final int CAMERA_IN_USE = 4; // 0x4
+ field public static final int CAMERA_MAX_IN_USE = 5; // 0x5
+ field public static final int CAMERA_UNAVAILABLE_DO_NOT_DISTURB = 6; // 0x6
+ field public static final int CAMERA_UNKNOWN_ERROR = 0; // 0x0
+ }
+
+ public final class CameraXConfig {
+ }
+
+ public static final class CameraXConfig.Builder {
+ method public androidx.camera.core.CameraXConfig build();
+ method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+ method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+ }
+
+ public static interface CameraXConfig.Provider {
+ method public androidx.camera.core.CameraXConfig getCameraXConfig();
+ }
+
+ public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraInfo, float, float);
+ }
+
+ public interface ExtendableBuilder<T> {
+ method public T build();
+ }
+
+ public final class FocusMeteringAction {
+ method public long getAutoCancelDurationInMillis();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+ method public boolean isAutoCancelEnabled();
+ field public static final int FLAG_AE = 2; // 0x2
+ field public static final int FLAG_AF = 1; // 0x1
+ field public static final int FLAG_AWB = 4; // 0x4
+ }
+
+ public static class FocusMeteringAction.Builder {
+ ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint);
+ ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction build();
+ method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+ method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+ }
+
+ public final class FocusMeteringResult {
+ method public boolean isFocusSuccessful();
+ }
+
+ public final class ImageAnalysis extends androidx.camera.core.UseCase {
+ method public void clearAnalyzer();
+ method public int getBackpressureStrategy();
+ method public int getImageQueueDepth();
+ method public int getTargetRotation();
+ method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method public void setTargetRotation(int);
+ field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+ field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+ }
+
+ public static interface ImageAnalysis.Analyzer {
+ method public void analyze(androidx.camera.core.ImageProxy);
+ }
+
+ public static final class ImageAnalysis.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageAnalysis> {
+ ctor public ImageAnalysis.Builder();
+ method public androidx.camera.core.ImageAnalysis build();
+ method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+ }
+
+ public final class ImageCapture extends androidx.camera.core.UseCase {
+ method public int getCaptureMode();
+ method public int getFlashMode();
+ method public int getTargetRotation();
+ method public void setCropAspectRatio(android.util.Rational);
+ method public void setFlashMode(int);
+ method public void setTargetRotation(int);
+ method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ method public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+ field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+ field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+ field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+ field public static final int ERROR_FILE_IO = 1; // 0x1
+ field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int FLASH_MODE_AUTO = 0; // 0x0
+ field public static final int FLASH_MODE_OFF = 2; // 0x2
+ field public static final int FLASH_MODE_ON = 1; // 0x1
+ }
+
+ public static final class ImageCapture.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageCapture> {
+ ctor public ImageCapture.Builder();
+ method public androidx.camera.core.ImageCapture build();
+ method public androidx.camera.core.ImageCapture.Builder setCaptureMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+ method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+ }
+
+ public static final class ImageCapture.Metadata {
+ ctor public ImageCapture.Metadata();
+ method public android.location.Location? getLocation();
+ method public boolean isReversedHorizontal();
+ method public boolean isReversedVertical();
+ method public void setLocation(android.location.Location?);
+ method public void setReversedHorizontal(boolean);
+ method public void setReversedVertical(boolean);
+ }
+
+ public abstract static class ImageCapture.OnImageCapturedCallback {
+ ctor public ImageCapture.OnImageCapturedCallback();
+ method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+ method public void onError(androidx.camera.core.ImageCaptureException);
+ }
+
+ public static interface ImageCapture.OnImageSavedCallback {
+ method public void onError(androidx.camera.core.ImageCaptureException);
+ method public void onImageSaved(androidx.camera.core.ImageCapture.OutputFileResults);
+ }
+
+ public static final class ImageCapture.OutputFileOptions {
+ }
+
+ public static final class ImageCapture.OutputFileOptions.Builder {
+ ctor public ImageCapture.OutputFileOptions.Builder(java.io.File);
+ ctor public ImageCapture.OutputFileOptions.Builder(android.content.ContentResolver, android.net.Uri, android.content.ContentValues);
+ ctor public ImageCapture.OutputFileOptions.Builder(java.io.OutputStream);
+ method public androidx.camera.core.ImageCapture.OutputFileOptions build();
+ method public androidx.camera.core.ImageCapture.OutputFileOptions.Builder setMetadata(androidx.camera.core.ImageCapture.Metadata);
+ }
+
+ public static class ImageCapture.OutputFileResults {
+ method public android.net.Uri? getSavedUri();
+ }
+
+ public class ImageCaptureException extends java.lang.Exception {
+ ctor public ImageCaptureException(int, String, Throwable?);
+ method public int getImageCaptureError();
+ }
+
+ public interface ImageInfo {
+ method public int getRotationDegrees();
+ method public long getTimestamp();
+ }
+
+ public interface ImageProxy extends java.lang.AutoCloseable {
+ method public void close();
+ method public android.graphics.Rect getCropRect();
+ method public int getFormat();
+ method public int getHeight();
+ method public androidx.camera.core.ImageInfo getImageInfo();
+ method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+ method public int getWidth();
+ method public void setCropRect(android.graphics.Rect?);
+ }
+
+ public static interface ImageProxy.PlaneProxy {
+ method public java.nio.ByteBuffer getBuffer();
+ method public int getPixelStride();
+ method public int getRowStride();
+ }
+
+ public class InitializationException extends java.lang.Exception {
+ ctor public InitializationException(String?);
+ ctor public InitializationException(String?, Throwable?);
+ ctor public InitializationException(Throwable?);
+ }
+
+ public class MeteringPoint {
+ method public float getSize();
+ }
+
+ public abstract class MeteringPointFactory {
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+ method public static float getDefaultPointSize();
+ }
+
+ public final class Preview extends androidx.camera.core.UseCase {
+ method public int getTargetRotation();
+ method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
+ method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
+ }
+
+ public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
+ ctor public Preview.Builder();
+ method public androidx.camera.core.Preview build();
+ method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.Preview.Builder setTargetName(String);
+ method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+ }
+
+ public static interface Preview.SurfaceProvider {
+ method public void onSurfaceRequested(androidx.camera.core.SurfaceRequest);
+ }
+
+ public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public SurfaceOrientedMeteringPointFactory(float, float);
+ ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+ }
+
+ public final class SurfaceRequest {
+ method public void addRequestCancellationListener(java.util.concurrent.Executor, Runnable);
+ method public android.util.Size getResolution();
+ method public void provideSurface(android.view.Surface, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceRequest.Result!>);
+ method public boolean willNotProvideSurface();
+ }
+
+ @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.Result {
+ method public abstract int getResultCode();
+ method public abstract android.view.Surface getSurface();
+ field public static final int RESULT_INVALID_SURFACE = 2; // 0x2
+ field public static final int RESULT_REQUEST_CANCELLED = 1; // 0x1
+ field public static final int RESULT_SURFACE_ALREADY_PROVIDED = 3; // 0x3
+ field public static final int RESULT_SURFACE_USED_SUCCESSFULLY = 0; // 0x0
+ field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
+ }
+
+ public class TorchState {
+ field public static final int OFF = 0; // 0x0
+ field public static final int ON = 1; // 0x1
+ }
+
+ public abstract class UseCase {
+ }
+
+ public interface ZoomState {
+ method public float getLinearZoom();
+ method public float getMaxZoomRatio();
+ method public float getMinZoomRatio();
+ method public float getZoomRatio();
+ }
+
+}
+
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java
index a4bdecf..30aa230 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java
@@ -33,7 +33,6 @@
import androidx.camera.testing.fakes.FakeCameraFactory;
import androidx.camera.testing.fakes.FakeCameraInfoInternal;
import androidx.camera.testing.fakes.FakeLifecycleOwner;
-import androidx.camera.testing.fakes.FakeUseCase;
import androidx.camera.testing.fakes.FakeUseCaseConfig;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -220,15 +219,6 @@
}
@Test
- public void requestingDefaultConfiguration_returnsDefaultConfiguration() {
- initCameraX();
- // Requesting a default configuration will throw if CameraX is not initialized.
- FakeUseCaseConfig config = CameraX.getDefaultUseCaseConfig(FakeUseCaseConfig.class);
- assertThat(config).isNotNull();
- assertThat(config.getTargetClass(null)).isEqualTo(FakeUseCase.class);
- }
-
- @Test
public void canGetCameraXContext() {
initCameraX();
Context context = CameraX.getContext();
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java
index 8b90e05..4dccf39 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java
@@ -19,7 +19,11 @@
import android.util.Size;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.testing.fakes.FakeUseCase;
/**
@@ -28,7 +32,6 @@
* <p>This is used to complement the {@link FakeUseCase} for testing instances where a use case of
* different type is created.
*/
-
public class FakeOtherUseCase extends UseCase {
private volatile boolean mIsDetached = false;
@@ -48,10 +51,34 @@
mIsDetached = true;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @Nullable
+ @Override
+ public UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory) {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @NonNull
+ @Override
+ public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+ throw new RuntimeException("Not implemented");
+ }
+
@NonNull
@Override
public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder() {
- return null;
+ throw new RuntimeException("Not implemented");
}
@Override
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageAnalysisDeviceTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageAnalysisDeviceTest.java
index 9d236f6..1fd8418 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageAnalysisDeviceTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageAnalysisDeviceTest.java
@@ -22,44 +22,29 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.content.Context;
-
import androidx.camera.core.impl.CameraInternal;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
-import androidx.camera.testing.fakes.FakeAppConfig;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
import androidx.test.annotation.UiThreadTest;
-import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ImageAnalysisDeviceTest {
private final CameraInternal mMockCameraInternal = mock(CameraInternal.class);
private final ImageAnalysis.Analyzer mMockAnalyzer = mock(ImageAnalysis.Analyzer.class);
+ private UseCaseConfigFactory mUseCaseConfigFactory;
@Before
- public void setup() throws ExecutionException, InterruptedException {
- CameraXConfig cameraXConfig = CameraXConfig.Builder.fromConfig(
- FakeAppConfig.create()).build();
-
- Context context = ApplicationProvider.getApplicationContext();
- CameraX.initialize(context, cameraXConfig).get();
- }
-
- @After
- public void tearDown() throws ExecutionException, InterruptedException, TimeoutException {
- CameraX.shutdown().get(10000, TimeUnit.MILLISECONDS);
+ public void setup() {
+ mUseCaseConfigFactory = new FakeUseCaseConfigFactory();
}
@Test
@@ -68,7 +53,7 @@
ImageAnalysis useCase = new ImageAnalysis.Builder().setBackpressureStrategy(
STRATEGY_KEEP_ONLY_LATEST).build();
- useCase.onAttach(mMockCameraInternal);
+ useCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
useCase.setAnalyzer(CameraXExecutors.mainThreadExecutor(), mMockAnalyzer);
@@ -81,7 +66,7 @@
ImageAnalysis useCase = new ImageAnalysis.Builder().setBackpressureStrategy(
STRATEGY_KEEP_ONLY_LATEST).build();
- useCase.onAttach(mMockCameraInternal);
+ useCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
useCase.setAnalyzer(CameraXExecutors.mainThreadExecutor(), mMockAnalyzer);
useCase.clearAnalyzer();
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageCaptureTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageCaptureTest.java
index e9d4858..b45ac106 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageCaptureTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageCaptureTest.java
@@ -24,35 +24,46 @@
import static org.mockito.Mockito.verify;
import android.app.Instrumentation;
-import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.ImageFormat;
+import android.graphics.Rect;
import android.util.Size;
+import androidx.annotation.NonNull;
import androidx.camera.core.impl.CaptureConfig;
import androidx.camera.core.impl.ImageCaptureConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.internal.CameraUseCaseAdapter;
-import androidx.camera.testing.fakes.FakeAppConfig;
import androidx.camera.testing.fakes.FakeCamera;
import androidx.camera.testing.fakes.FakeCameraControl;
import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
-import androidx.test.core.app.ApplicationProvider;
+import androidx.camera.testing.fakes.FakeImageInfo;
+import androidx.camera.testing.fakes.FakeImageProxy;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
+import androidx.exifinterface.media.ExifInterface;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Instrument tests for {@link ImageCapture}.
@@ -64,13 +75,7 @@
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
@Before
- public void setup() throws ExecutionException, InterruptedException {
- CameraXConfig cameraXConfig = CameraXConfig.Builder.fromConfig(
- FakeAppConfig.create()).build();
-
- Context context = ApplicationProvider.getApplicationContext();
- CameraX.initialize(context, cameraXConfig).get();
-
+ public void setup() {
FakeCamera fakeCamera = new FakeCamera("fakeCameraId");
FakeCameraDeviceSurfaceManager fakeCameraDeviceSurfaceManager =
@@ -79,14 +84,48 @@
ImageCaptureConfig.class,
new Size(640, 480));
+ UseCaseConfigFactory useCaseConfigFactory = new FakeUseCaseConfigFactory();
+
mCameraUseCaseAdapter = new CameraUseCaseAdapter(fakeCamera,
new LinkedHashSet<>(Collections.singleton(fakeCamera)),
- fakeCameraDeviceSurfaceManager);
+ fakeCameraDeviceSurfaceManager,
+ useCaseConfigFactory);
}
- @After
- public void tearDown() throws ExecutionException, InterruptedException, TimeoutException {
- CameraX.shutdown().get(10000, TimeUnit.MILLISECONDS);
+ @Test
+ public void getDispatchCropRect_dispatchBufferRotated90() {
+ assertGetDispatchCropRect(90, new Size(4, 6), new Rect(3, 0, 4, 1));
+ }
+
+ @Test
+ public void getDispatchCropRect_dispatchBufferRotated180() {
+ assertGetDispatchCropRect(180, new Size(6, 4), new Rect(5, 3, 6, 4));
+ }
+
+ @Test
+ public void getDispatchCropRect_dispatchBufferRotated270() {
+ assertGetDispatchCropRect(270, new Size(4, 6), new Rect(0, 5, 1, 6));
+ }
+
+ @Test
+ public void getDispatchCropRect_dispatchBufferRotated0() {
+ assertGetDispatchCropRect(0, new Size(6, 4), new Rect(0, 0, 1, 1));
+ }
+
+ private void assertGetDispatchCropRect(int outputDegrees, Size dispatchResolution,
+ Rect dispatchRect) {
+ // Arrange:
+ // Surface crop rect stays the same regardless of HAL rotations.
+ Rect surfaceCropRect = new Rect(0, 0, 1, 1);
+ // Exif degrees being 0 means HAL consumed the target rotation.
+ int exifRotationDegrees = 0;
+
+ // Act.
+ Rect dispatchCropRect = ImageCapture.ImageCaptureRequest.getDispatchCropRect(
+ surfaceCropRect, outputDegrees, dispatchResolution, exifRotationDegrees);
+
+ // Assert.
+ assertThat(dispatchCropRect).isEqualTo(dispatchRect);
}
@Test
@@ -183,6 +222,101 @@
}
@Test
+ public void dispatchImage_cropRectIsUpdatedBasedOnExifOrientation()
+ throws InterruptedException, IOException {
+ // Arrange: assume the sensor buffer is 6x4, the crop rect is (0, 0) - (2, 1) and the
+ // rotation degrees is 90°.
+ Semaphore semaphore = new Semaphore(0);
+ AtomicReference<ImageProxy> imageProxyReference = new AtomicReference<>();
+ ImageCapture.ImageCaptureRequest request = new ImageCapture.ImageCaptureRequest(
+ /*rotationDegrees*/90,
+ /*jpegQuality*/100,
+ /*targetRatio*/ null,
+ /*viewPortCropRect*/ new Rect(0, 0, 2, 1),
+ CameraXExecutors.mainThreadExecutor(),
+ new ImageCapture.OnImageCapturedCallback() {
+ @Override
+ public void onCaptureSuccess(@NonNull ImageProxy image) {
+ super.onCaptureSuccess(image);
+ imageProxyReference.set(image);
+ semaphore.release();
+ }
+ });
+
+ // Act: dispatch a image that has been rotated in the HAL. After 90° rotation the buffer
+ // becomes 4x6 and orientation is normal.
+ request.dispatchImage(createJpegImageProxy(4, 6, ExifInterface.ORIENTATION_NORMAL));
+ semaphore.tryAcquire(3, TimeUnit.SECONDS);
+
+ // Assert: that the rotation is 0 and the crop rect has been updated.
+ assertThat(imageProxyReference.get().getImageInfo().getRotationDegrees()).isEqualTo(0);
+ assertThat(imageProxyReference.get().getCropRect()).isEqualTo(new Rect(3, 0, 4, 2));
+ }
+
+ /**
+ * Creates a {@link ImageProxy} with given width, height and exif orientation.
+ *
+ * @param exifOrientation orientation integers defined in {@link ExifInterface}.
+ */
+ private ImageProxy createJpegImageProxy(int width, int height,
+ int exifOrientation) throws IOException {
+ // Create a temporary jpeg file with given width/height.
+ File jpegFile = File.createTempFile("fake_jpeg_with_exif", "jpeg",
+ mInstrumentation.getContext().getCacheDir());
+ jpegFile.deleteOnExit();
+ try (FileOutputStream out = new FileOutputStream(jpegFile)) {
+ Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).compress(
+ Bitmap.CompressFormat.JPEG, 100, out);
+ }
+
+ // Save the exif orientation to the jpeg file.
+ ExifInterface exifInterface = new ExifInterface(jpegFile.getAbsolutePath());
+ exifInterface.setAttribute(androidx.exifinterface.media.ExifInterface.TAG_ORIENTATION,
+ String.valueOf(exifOrientation));
+ exifInterface.saveAttributes();
+
+ // Load the jpeg file into a ByteBuffer.
+ ByteBuffer byteData;
+ try (FileInputStream inputStream = new FileInputStream(jpegFile)) {
+ byte[] buffer = new byte[1024];
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ int read;
+ while (true) {
+ read = inputStream.read(buffer);
+ if (read == -1) {
+ break;
+ }
+ outStream.write(buffer, 0, read);
+ }
+ byteData = ByteBuffer.wrap(outStream.toByteArray());
+ }
+
+ // Create a FakeImageProxy from the ByteBuffer.
+ FakeImageProxy fakeImageProxy = new FakeImageProxy(new FakeImageInfo());
+ fakeImageProxy.setFormat(ImageFormat.JPEG);
+ ImageProxy.PlaneProxy planeProxy = new ImageProxy.PlaneProxy() {
+
+ @Override
+ public int getRowStride() {
+ return 0;
+ }
+
+ @Override
+ public int getPixelStride() {
+ return 0;
+ }
+
+ @NonNull
+ @Override
+ public ByteBuffer getBuffer() {
+ return byteData;
+ }
+ };
+ fakeImageProxy.setPlanes(new ImageProxy.PlaneProxy[]{planeProxy});
+ return fakeImageProxy;
+ }
+
+ @Test
public void setFlashModeDuringPictureTaken() throws InterruptedException {
// Arrange.
ImageCapture imageCapture = createImageCapture();
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ProcessingImageReaderDeviceTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/ProcessingImageReaderDeviceTest.kt
index 81b3932..e915887d 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ProcessingImageReaderDeviceTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ProcessingImageReaderDeviceTest.kt
@@ -127,8 +127,12 @@
imageWriter.queueInputImage(image)
val fakeCameraCaptureResult = FakeCameraCaptureResult()
fakeCameraCaptureResult.timestamp = timestamp
- val tagBundle = TagBundle.create(Pair(mCaptureBundle.hashCode().toString(),
- captureId))
+ val tagBundle = TagBundle.create(
+ Pair(
+ mCaptureBundle.hashCode().toString(),
+ captureId
+ )
+ )
fakeCameraCaptureResult.setTag(tagBundle)
callback.onCaptureCompleted(fakeCameraCaptureResult)
}
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java
index 0b3c829..fc61519 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.util.Size;
@@ -34,8 +35,10 @@
import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.SessionConfig;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.testing.fakes.FakeUseCase;
import androidx.camera.testing.fakes.FakeUseCaseConfig;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -47,10 +50,12 @@
@RunWith(AndroidJUnit4.class)
public class UseCaseTest {
private CameraInternal mMockCameraInternal;
+ private UseCaseConfigFactory mUseCaseConfigFactory;
@Before
public void setup() {
mMockCameraInternal = mock(CameraInternal.class);
+ mUseCaseConfigFactory = new FakeUseCaseConfigFactory();
}
@Test
@@ -72,7 +77,7 @@
"UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
- testUseCase.onAttach(mMockCameraInternal);
+ testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
testUseCase.onDetach(mMockCameraInternal);
testUseCase.activate();
@@ -85,7 +90,7 @@
FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
"UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
- testUseCase.onAttach(mMockCameraInternal);
+ testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
testUseCase.activate();
verify(mMockCameraInternal, times(1)).onUseCaseActive(testUseCase);
@@ -96,7 +101,7 @@
FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
"UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
- testUseCase.onAttach(mMockCameraInternal);
+ testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
testUseCase.deactivate();
verify(mMockCameraInternal, times(1)).onUseCaseInactive(testUseCase);
@@ -107,7 +112,7 @@
FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
"UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
- testUseCase.onAttach(mMockCameraInternal);
+ testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
testUseCase.update();
verify(mMockCameraInternal, times(1)).onUseCaseUpdated(testUseCase);
@@ -118,40 +123,12 @@
FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
"UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
- testUseCase.onAttach(mMockCameraInternal);
+ testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
testUseCase.notifyReset();
verify(mMockCameraInternal, times(1)).onUseCaseReset(testUseCase);
}
- @Test(expected = IllegalStateException.class)
- public void updateUseCaseConfig_beforeUseCaseIsAttached_throwException() {
- FakeUseCaseConfig.Builder configBuilder = new FakeUseCaseConfig.Builder();
- TestUseCase testUseCase = new TestUseCase(configBuilder.getUseCaseConfig());
- testUseCase.updateUseCaseConfig(configBuilder.getUseCaseConfig());
- }
-
- @Test
- public void updateUseCaseConfig_afterUseCaseIsAttached() {
- String originalName = "UseCase";
- FakeUseCaseConfig.Builder configBuilder =
- new FakeUseCaseConfig.Builder().setTargetName(originalName);
-
- TestUseCase testUseCase = new TestUseCase(configBuilder.getUseCaseConfig());
- String originalRetrievedName = testUseCase.getUseCaseConfig().getTargetName();
-
- // NOTE: Updating the use case name is probably a very bad idea in most cases. However,
- // we'll do it here for the sake of this test.
- String newName = "UseCase-New";
- configBuilder.setTargetName(newName);
- testUseCase.onAttach(mMockCameraInternal);
- testUseCase.updateUseCaseConfig(configBuilder.getUseCaseConfig());
- String newRetrievedName = testUseCase.getUseCaseConfig().getTargetName();
-
- assertThat(originalRetrievedName).isEqualTo(originalName);
- assertThat(newRetrievedName).isEqualTo(newName);
- }
-
@Test
public void useCaseConfig_keepOptionPriority() {
FakeUseCaseConfig.Builder builder = new FakeUseCaseConfig.Builder();
@@ -159,7 +136,7 @@
builder.getMutableConfig().insertOption(opt, ALWAYS_OVERRIDE, 1);
FakeUseCase fakeUseCase = builder.build();
- UseCaseConfig<?> useCaseConfig = fakeUseCase.getUseCaseConfig();
+ UseCaseConfig<?> useCaseConfig = fakeUseCase.getCurrentConfig();
assertThat(useCaseConfig.getOptionPriority(opt)).isEqualTo(ALWAYS_OVERRIDE);
}
@@ -173,7 +150,7 @@
testUseCase.updateSuggestedResolution(new Size(640, 480));
assertThat(testUseCase.getAttachedSurfaceResolution()).isNotNull();
- testUseCase.onAttach(mMockCameraInternal);
+ testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
testUseCase.onDetach(mMockCameraInternal);
assertThat(testUseCase.getAttachedSurfaceResolution()).isNull();
@@ -188,12 +165,38 @@
testUseCase.setViewPortCropRect(new Rect());
assertThat(testUseCase.getViewPortCropRect()).isNotNull();
- testUseCase.onAttach(mMockCameraInternal);
+ testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
testUseCase.onDetach(mMockCameraInternal);
assertThat(testUseCase.getViewPortCropRect()).isNull();
}
+ @Test
+ public void mergeConfigs() {
+ int cameraDefaultPriority = 4;
+ FakeUseCaseConfig defaultConfig = new FakeUseCaseConfig.Builder()
+ .setTargetName("UseCase-camera")
+ .setBufferFormat(ImageFormat.RAW10)
+ .setSurfaceOccupancyPriority(cameraDefaultPriority).getUseCaseConfig();
+
+ int useCaseImageFormat = ImageFormat.YUV_420_888;
+ FakeUseCaseConfig useCaseConfig = new FakeUseCaseConfig.Builder()
+ .setTargetName("UseCase-useCase")
+ .setBufferFormat(useCaseImageFormat).getUseCaseConfig();
+
+ String extendedTargetName = "UseCase-extended";
+ FakeUseCaseConfig extendedConfig = new FakeUseCaseConfig.Builder()
+ .setTargetName(extendedTargetName).getUseCaseConfig();
+
+ TestUseCase testUseCase = new TestUseCase(useCaseConfig);
+
+ UseCaseConfig<?> mergedConfig = testUseCase.mergeConfigs(extendedConfig, defaultConfig);
+
+ assertThat(mergedConfig.getSurfaceOccupancyPriority()).isEqualTo(cameraDefaultPriority);
+ assertThat(mergedConfig.getInputFormat()).isEqualTo(useCaseImageFormat);
+ assertThat(mergedConfig.getTargetName()).isEqualTo(extendedTargetName);
+ }
+
static class TestUseCase extends FakeUseCase {
TestUseCase(FakeUseCaseConfig config) {
super(config);
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.java
index 6e955dc..3476d6f 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.java
@@ -28,10 +28,12 @@
import androidx.camera.core.UseCase;
import androidx.camera.core.ViewPort;
import androidx.camera.core.impl.CameraInternal;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.testing.fakes.FakeCamera;
import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
import androidx.camera.testing.fakes.FakeUseCase;
import androidx.camera.testing.fakes.FakeUseCaseConfig;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
@@ -49,12 +51,14 @@
public class CameraUseCaseAdapterTest {
FakeCameraDeviceSurfaceManager mFakeCameraDeviceSurfaceManager;
FakeCamera mFakeCamera;
+ UseCaseConfigFactory mUseCaseConfigFactory;
LinkedHashSet<CameraInternal> mFakeCameraSet = new LinkedHashSet<>();
@Before
public void setUp() {
mFakeCameraDeviceSurfaceManager = new FakeCameraDeviceSurfaceManager();
mFakeCamera = new FakeCamera();
+ mUseCaseConfigFactory = new FakeUseCaseConfigFactory();
mFakeCameraSet.add(mFakeCamera);
}
@@ -62,7 +66,8 @@
public void attachUseCases() throws CameraUseCaseAdapter.CameraException {
CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
mFakeCameraSet,
- mFakeCameraDeviceSurfaceManager);
+ mFakeCameraDeviceSurfaceManager,
+ mUseCaseConfigFactory);
FakeUseCase fakeUseCase = new FakeUseCase();
cameraUseCaseAdapter.addUseCases(Collections.singleton(fakeUseCase));
@@ -74,7 +79,8 @@
public void detachUseCases() throws CameraUseCaseAdapter.CameraException {
CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
mFakeCameraSet,
- mFakeCameraDeviceSurfaceManager);
+ mFakeCameraDeviceSurfaceManager,
+ mUseCaseConfigFactory);
FakeUseCase fakeUseCase = new FakeUseCase();
cameraUseCaseAdapter.addUseCases(Collections.singleton(fakeUseCase));
cameraUseCaseAdapter.removeUseCases(Collections.singleton(fakeUseCase));
@@ -86,7 +92,8 @@
public void closeCameraUseCaseAdapter() throws CameraUseCaseAdapter.CameraException {
CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
mFakeCameraSet,
- mFakeCameraDeviceSurfaceManager);
+ mFakeCameraDeviceSurfaceManager,
+ mUseCaseConfigFactory);
FakeUseCase fakeUseCase = new FakeUseCase();
cameraUseCaseAdapter.addUseCases(Collections.singleton(fakeUseCase));
cameraUseCaseAdapter.detachUseCases();
@@ -99,7 +106,8 @@
public void cameraIdEquals() {
CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
mFakeCameraSet,
- mFakeCameraDeviceSurfaceManager);
+ mFakeCameraDeviceSurfaceManager,
+ mUseCaseConfigFactory);
CameraUseCaseAdapter.CameraId otherCameraId =
CameraUseCaseAdapter.generateCameraId(mFakeCameraSet);
@@ -111,11 +119,13 @@
public void cameraEquivalent() {
CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
mFakeCameraSet,
- mFakeCameraDeviceSurfaceManager);
+ mFakeCameraDeviceSurfaceManager,
+ mUseCaseConfigFactory);
CameraUseCaseAdapter otherCameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
mFakeCameraSet,
- mFakeCameraDeviceSurfaceManager);
+ mFakeCameraDeviceSurfaceManager,
+ mUseCaseConfigFactory);
assertThat(cameraUseCaseAdapter.isEquivalent(otherCameraUseCaseAdapter)).isTrue();
}
@@ -124,12 +134,13 @@
public void useCase_onAttach() throws CameraUseCaseAdapter.CameraException {
CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
mFakeCameraSet,
- mFakeCameraDeviceSurfaceManager);
+ mFakeCameraDeviceSurfaceManager,
+ mUseCaseConfigFactory);
FakeUseCase fakeUseCase = spy(new FakeUseCase());
cameraUseCaseAdapter.addUseCases(Collections.singleton(fakeUseCase));
- verify(fakeUseCase).onAttach(mFakeCamera);
+ verify(fakeUseCase).onAttach(mFakeCamera, mUseCaseConfigFactory);
}
@Test
@@ -137,7 +148,8 @@
public void useCase_onDetach() throws CameraUseCaseAdapter.CameraException {
CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
mFakeCameraSet,
- mFakeCameraDeviceSurfaceManager);
+ mFakeCameraDeviceSurfaceManager,
+ mUseCaseConfigFactory);
FakeUseCase fakeUseCase = spy(new FakeUseCase());
cameraUseCaseAdapter.addUseCases(Collections.singleton(fakeUseCase));
@@ -151,7 +163,8 @@
public void eventCallbackOnBind() throws CameraUseCaseAdapter.CameraException {
CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
mFakeCameraSet,
- mFakeCameraDeviceSurfaceManager);
+ mFakeCameraDeviceSurfaceManager,
+ mUseCaseConfigFactory);
UseCase.EventCallback callback = mock(UseCase.EventCallback.class);
FakeUseCase fakeUseCase =
@@ -166,7 +179,8 @@
public void eventCallbackOnUnbind() throws CameraUseCaseAdapter.CameraException {
CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
mFakeCameraSet,
- mFakeCameraDeviceSurfaceManager);
+ mFakeCameraDeviceSurfaceManager,
+ mUseCaseConfigFactory);
UseCase.EventCallback callback = mock(UseCase.EventCallback.class);
FakeUseCase fakeUseCase =
@@ -189,7 +203,8 @@
// Arrange: set up adapter with aspect ratio 1.
CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
mFakeCameraSet,
- mFakeCameraDeviceSurfaceManager);
+ mFakeCameraDeviceSurfaceManager,
+ mUseCaseConfigFactory);
cameraUseCaseAdapter.setViewPort(
new ViewPort.Builder(aspectRatio1, Surface.ROTATION_0).build());
FakeUseCase fakeUseCase = spy(new FakeUseCase());
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/UseCaseOccupancyTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/UseCaseOccupancyTest.java
deleted file mode 100644
index 1079d6e..0000000
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/UseCaseOccupancyTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2020 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 androidx.camera.core.internal;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-
-import androidx.camera.core.CameraX;
-import androidx.camera.core.CameraXConfig;
-import androidx.camera.core.ImageCapture;
-import androidx.camera.core.VideoCapture;
-import androidx.camera.testing.fakes.FakeAppConfig;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-/** JUnit test cases for {@link UseCaseOccupancy} class. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class UseCaseOccupancyTest {
-
- @Before
- public void setUp() throws ExecutionException, InterruptedException {
- Context context = ApplicationProvider.getApplicationContext();
- CameraXConfig cameraXConfig = CameraXConfig.Builder.fromConfig(
- FakeAppConfig.create()).build();
- CameraX.initialize(context, cameraXConfig).get();
- }
-
- @After
- public void tearDown() throws ExecutionException, InterruptedException, TimeoutException {
- CameraX.shutdown().get(10000, TimeUnit.MILLISECONDS);
- }
-
- @Test
- public void failedWhenBindTooManyImageCapture() {
- ImageCapture useCase1 = createImageCapture();
- ImageCapture useCase2 = createImageCapture();
-
- assertThat(UseCaseOccupancy.checkUseCaseLimitNotExceeded(
- Arrays.asList(useCase1, useCase2))).isFalse();
- }
-
- @Test
- public void failedWhenBindTooManyVideoCapture() {
- VideoCapture useCase1 = new VideoCapture.Builder().build();
- VideoCapture useCase2 = new VideoCapture.Builder().build();
-
- assertThat(UseCaseOccupancy.checkUseCaseLimitNotExceeded(
- Arrays.asList(useCase1, useCase2))).isFalse();
- }
-
- @Test
- public void passWhenNotBindTooManyImageVideoCapture() {
- ImageCapture imageCapture = createImageCapture();
- VideoCapture videoCapture = new VideoCapture.Builder().build();
-
- assertThat(UseCaseOccupancy.checkUseCaseLimitNotExceeded(
- Arrays.asList(imageCapture, videoCapture))).isTrue();
- }
-
- // TODO remove when UseCase does not require
- private ImageCapture createImageCapture() {
- return new ImageCapture.Builder()
- .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
- .setFlashMode(ImageCapture.FLASH_MODE_OFF)
- .setCaptureOptionUnpacker((config, builder) -> { })
- .setSessionOptionUnpacker((config, builder) -> { })
- .build();
- }
-}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/CameraX.java b/camera/camera-core/src/main/java/androidx/camera/core/CameraX.java
index 8753394..75eedea 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/CameraX.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/CameraX.java
@@ -36,7 +36,6 @@
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.core.impl.CameraRepository;
import androidx.camera.core.impl.CameraThreadConfig;
-import androidx.camera.core.impl.UseCaseConfig;
import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.impl.utils.futures.FutureCallback;
@@ -141,40 +140,6 @@
}
/**
- * Returns the {@link CameraDeviceSurfaceManager} which can be used to query for valid surface
- * configurations.
- *
- * @hide
- */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public static CameraDeviceSurfaceManager getSurfaceManager() {
- CameraX cameraX = checkInitialized();
-
- return cameraX.getCameraDeviceSurfaceManager();
- }
-
- /**
- * Returns the default configuration for the given use case configuration type.
- *
- * <p>The options contained in this configuration serve as fallbacks if they are not included in
- * the user-provided configuration used to create a use case.
- *
- * @param configType the configuration type
- * @return the default configuration for the given configuration type
- * @throws IllegalStateException if CameraX has not yet been initialized.
- * @hide
- */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Nullable
- public static <C extends UseCaseConfig<?>> C getDefaultUseCaseConfig(
- @NonNull Class<C> configType) {
- CameraX cameraX = checkInitialized();
-
- return cameraX.getDefaultConfigFactory().getConfig(configType);
- }
-
- /**
* Initializes CameraX with the given context and application configuration.
*
* <p>The context enables CameraX to obtain access to necessary services, including the camera
@@ -530,7 +495,14 @@
return mCameraRepository;
}
- private UseCaseConfigFactory getDefaultConfigFactory() {
+ /**
+ * Returns the {@link UseCaseConfigFactory} instance.
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public UseCaseConfigFactory getDefaultConfigFactory() {
if (mDefaultConfigFactory == null) {
throw new IllegalStateException("CameraX not initialized yet.");
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
index 5813f51..adb7ceb 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
@@ -49,6 +49,7 @@
import androidx.annotation.RestrictTo.Scope;
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.core.impl.CaptureConfig;
+import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.ConfigProvider;
import androidx.camera.core.impl.DeferrableSurface;
import androidx.camera.core.impl.ImageAnalysisConfig;
@@ -60,6 +61,7 @@
import androidx.camera.core.impl.OptionsBundle;
import androidx.camera.core.impl.SessionConfig;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.impl.utils.Threads;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.internal.TargetConfig;
@@ -174,7 +176,7 @@
super(config);
// Get the combined configuration with defaults
- ImageAnalysisConfig combinedConfig = (ImageAnalysisConfig) getUseCaseConfig();
+ ImageAnalysisConfig combinedConfig = (ImageAnalysisConfig) getCurrentConfig();
if (combinedConfig.getBackpressureStrategy(DEFAULT_BACKPRESSURE_STRATEGY)
== STRATEGY_BLOCK_PRODUCER) {
@@ -390,7 +392,7 @@
*/
@BackpressureStrategy
public int getBackpressureStrategy() {
- return ((ImageAnalysisConfig) getUseCaseConfig()).getBackpressureStrategy(
+ return ((ImageAnalysisConfig) getCurrentConfig()).getBackpressureStrategy(
DEFAULT_BACKPRESSURE_STRATEGY);
}
@@ -409,7 +411,7 @@
* @see ImageAnalysis.Builder#setBackpressureStrategy(int)
*/
public int getImageQueueDepth() {
- return ((ImageAnalysisConfig) getUseCaseConfig()).getImageQueueDepth(
+ return ((ImageAnalysisConfig) getCurrentConfig()).getImageQueueDepth(
DEFAULT_IMAGE_QUEUE_DEPTH);
}
@@ -435,16 +437,11 @@
*
* @hide
*/
+ @RestrictTo(Scope.LIBRARY_GROUP)
@Override
@Nullable
- @RestrictTo(Scope.LIBRARY_GROUP)
- public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
- ImageAnalysisConfig defaults = CameraX.getDefaultUseCaseConfig(ImageAnalysisConfig.class);
- if (defaults != null) {
- return Builder.fromConfig(defaults);
- }
-
- return null;
+ public UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory) {
+ return factory.getConfig(ImageAnalysisConfig.class);
}
/**
@@ -473,8 +470,20 @@
@NonNull
@RestrictTo(Scope.LIBRARY_GROUP)
@Override
+ public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+ return ImageAnalysis.Builder.fromConfig(config);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder() {
- return Builder.fromConfig((ImageAnalysisConfig) getUseCaseConfig());
+ return Builder.fromConfig((ImageAnalysisConfig) getCurrentConfig());
}
/**
@@ -486,7 +495,7 @@
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
protected Size onSuggestedResolutionUpdated(@NonNull Size suggestedResolution) {
- final ImageAnalysisConfig config = (ImageAnalysisConfig) getUseCaseConfig();
+ final ImageAnalysisConfig config = (ImageAnalysisConfig) getCurrentConfig();
SessionConfig.Builder sessionConfigBuilder = createPipeline(getCameraId(), config,
suggestedResolution);
@@ -641,6 +650,19 @@
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
+ static Builder fromConfig(@NonNull Config configuration) {
+ return new Builder(MutableOptionsBundle.from(configuration));
+ }
+
+ /**
+ * Generates a Builder from another Config object.
+ *
+ * @param configuration An immutable configuration to pre-populate this builder.
+ * @return The new Builder.
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
public static Builder fromConfig(@NonNull ImageAnalysisConfig configuration) {
return new Builder(MutableOptionsBundle.from(configuration));
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
index 40cccc2..d192fb7 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
@@ -39,11 +39,15 @@
import static androidx.camera.core.impl.ImageCaptureConfig.OPTION_USE_CASE_EVENT_CALLBACK;
import static androidx.camera.core.impl.ImageInputConfig.OPTION_INPUT_FORMAT;
import static androidx.camera.core.impl.UseCaseConfig.OPTION_CAMERA_SELECTOR;
+import static androidx.camera.core.internal.utils.ImageUtil.min;
+import static androidx.camera.core.internal.utils.ImageUtil.sizeToVertexes;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.graphics.ImageFormat;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.location.Location;
import android.media.Image;
import android.media.ImageReader;
@@ -81,6 +85,7 @@
import androidx.camera.core.impl.CaptureConfig;
import androidx.camera.core.impl.CaptureProcessor;
import androidx.camera.core.impl.CaptureStage;
+import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.ConfigProvider;
import androidx.camera.core.impl.DeferrableSurface;
import androidx.camera.core.impl.ImageCaptureConfig;
@@ -93,6 +98,7 @@
import androidx.camera.core.impl.OptionsBundle;
import androidx.camera.core.impl.SessionConfig;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.impl.utils.CameraOrientationUtil;
import androidx.camera.core.impl.utils.Exif;
import androidx.camera.core.impl.utils.Threads;
@@ -311,7 +317,7 @@
ImageCapture(@NonNull ImageCaptureConfig userConfig) {
super(userConfig);
- ImageCaptureConfig useCaseConfig = (ImageCaptureConfig) getUseCaseConfig();
+ ImageCaptureConfig useCaseConfig = (ImageCaptureConfig) getCurrentConfig();
if (useCaseConfig.containsOption(OPTION_IMAGE_CAPTURE_MODE)) {
mCaptureMode = useCaseConfig.getCaptureMode();
@@ -417,16 +423,23 @@
*
* @hide
*/
+ @RestrictTo(Scope.LIBRARY_GROUP)
@Override
@Nullable
- @RestrictTo(Scope.LIBRARY_GROUP)
- public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
- ImageCaptureConfig defaults = CameraX.getDefaultUseCaseConfig(ImageCaptureConfig.class);
- if (defaults != null) {
- return Builder.fromConfig(defaults);
- }
+ public UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory) {
+ return factory.getConfig(ImageCaptureConfig.class);
+ }
- return null;
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+ return Builder.fromConfig(config);
}
/**
@@ -438,7 +451,7 @@
@RestrictTo(Scope.LIBRARY_GROUP)
@Override
public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder() {
- return Builder.fromConfig((ImageCaptureConfig) getUseCaseConfig());
+ return Builder.fromConfig((ImageCaptureConfig) getCurrentConfig());
}
/**
@@ -462,7 +475,7 @@
public int getFlashMode() {
synchronized (mLockedFlashMode) {
return mFlashMode != FLASH_MODE_UNKNOWN ? mFlashMode
- : ((ImageCaptureConfig) getUseCaseConfig()).getFlashMode(DEFAULT_FLASH_MODE);
+ : ((ImageCaptureConfig) getCurrentConfig()).getFlashMode(DEFAULT_FLASH_MODE);
}
}
@@ -1095,7 +1108,7 @@
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
public void onAttached() {
- ImageCaptureConfig useCaseConfig = (ImageCaptureConfig) getUseCaseConfig();
+ ImageCaptureConfig useCaseConfig = (ImageCaptureConfig) getCurrentConfig();
CaptureConfig.Builder captureBuilder = CaptureConfig.Builder.createFrom(useCaseConfig);
mCaptureConfig = captureBuilder.build();
@@ -1132,7 +1145,7 @@
@RestrictTo(Scope.LIBRARY_GROUP)
protected Size onSuggestedResolutionUpdated(@NonNull Size suggestedResolution) {
mSessionConfigBuilder = createPipeline(getCameraId(),
- (ImageCaptureConfig) getUseCaseConfig(), suggestedResolution);
+ (ImageCaptureConfig) getCurrentConfig(), suggestedResolution);
updateSessionConfig(mSessionConfigBuilder.build());
@@ -2056,8 +2069,8 @@
return;
}
- Size dispatchResolution = null;
- int dispatchRotation = 0;
+ Size dispatchResolution;
+ int dispatchRotationDegrees = 0;
if (image.getFormat() == ImageFormat.JPEG) {
// JPEG needs to have rotation/crop based on the EXIF
@@ -2074,7 +2087,7 @@
buffer.rewind();
dispatchResolution = new Size(exif.getWidth(), exif.getHeight());
- dispatchRotation = exif.getRotation();
+ dispatchRotationDegrees = exif.getRotation();
} catch (IOException e) {
notifyCallbackError(ERROR_FILE_IO, "Unable to parse JPEG exif", e);
image.close();
@@ -2082,13 +2095,14 @@
}
} else {
// All other formats take the rotation based simply on the target rotation
- dispatchRotation = mRotationDegrees;
+ dispatchResolution = new Size(image.getWidth(), image.getHeight());
+ dispatchRotationDegrees = mRotationDegrees;
}
// Construct the ImageProxy with the updated rotation & crop for the output
ImageInfo imageInfo = ImmutableImageInfo.create(
image.getImageInfo().getTagBundle(),
- image.getImageInfo().getTimestamp(), dispatchRotation);
+ image.getImageInfo().getTimestamp(), dispatchRotationDegrees);
final ImageProxy dispatchedImageProxy = new SettableImageProxy(image,
dispatchResolution,
@@ -2097,12 +2111,13 @@
// Update the crop rect aspect ratio after it has been rotated into the buffer
// orientation
if (mViewPortCropRect != null) {
- // If Viewport is present, use the crop rect based on Viewport.
- dispatchedImageProxy.setCropRect(mViewPortCropRect);
+ // If Viewport is present, use the Viewport-based crop rect.
+ dispatchedImageProxy.setCropRect(getDispatchCropRect(mViewPortCropRect,
+ mRotationDegrees, dispatchResolution, dispatchRotationDegrees));
} else if (mTargetRatio != null) {
// Fall back to crop aspect ratio if view port is not available.
Rational dispatchRatio = mTargetRatio;
- if ((dispatchRotation % 180) != 0) {
+ if ((dispatchRotationDegrees % 180) != 0) {
dispatchRatio = new Rational(
/* invert the ratio numerator=*/ mTargetRatio.getDenominator(),
/* invert the ratio denominator=*/ mTargetRatio.getNumerator());
@@ -2128,6 +2143,50 @@
}
}
+ /**
+ * Corrects crop rect based on JPEG exif rotation.
+ *
+ * <p> The original crop rect is calculated based on camera sensor buffer. On some devices,
+ * the buffer is rotated before being passed to users, in which case the crop rect also
+ * needs additional transformations.
+ *
+ * <p> There are two most common scenarios: 1) exif rotation is 0, or 2) exif rotation
+ * equals output rotation. 1) means the HAL rotated the buffer based on target
+ * rotation. 2) means HAL no-oped on the rotation. Theoretically only 1) needs
+ * additional transformations, but this method is also generic enough to handle all possible
+ * HAL rotations.
+ */
+ @NonNull
+ static Rect getDispatchCropRect(@NonNull Rect surfaceCropRect, int surfaceToOutputDegrees,
+ @NonNull Size dispatchResolution, int dispatchToOutputDegrees) {
+ // There are 3 coordinate systems: surface, dispatch and output. Surface is where
+ // the original crop rect is defined. We need to figure out what HAL
+ // has done to the buffer (the surface->dispatch mapping) and apply the same
+ // transformation to the crop rect.
+ // The surface->dispatch mapping is calculated by inverting a dispatch->surface mapping.
+
+ Matrix matrix = new Matrix();
+ // Apply the dispatch->surface rotation.
+ matrix.setRotate(dispatchToOutputDegrees - surfaceToOutputDegrees);
+ // Apply the dispatch->surface translation. The translation is calculated by
+ // compensating for the offset caused by the dispatch->surface rotation.
+ float[] vertexes = sizeToVertexes(dispatchResolution);
+ matrix.mapPoints(vertexes);
+ float left = min(vertexes[0], vertexes[2], vertexes[4], vertexes[6]);
+ float top = min(vertexes[1], vertexes[3], vertexes[5], vertexes[7]);
+ matrix.postTranslate(-left, -top);
+ // Inverting the dispatch->surface mapping to get the surface->dispatch mapping.
+ matrix.invert(matrix);
+
+ // Apply the surface->dispatch mapping to surface crop rect.
+ RectF dispatchCropRectF = new RectF();
+ matrix.mapRect(dispatchCropRectF, new RectF(surfaceCropRect));
+ dispatchCropRectF.sort();
+ Rect dispatchCropRect = new Rect();
+ dispatchCropRectF.round(dispatchCropRect);
+ return dispatchCropRect;
+ }
+
void notifyCallbackError(final @ImageCaptureError int imageCaptureError,
final String message, final Throwable cause) {
// Check to make sure image hasn't been already dispatched or error has been notified
@@ -2182,7 +2241,20 @@
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public static Builder fromConfig(@NonNull ImageCaptureConfig configuration) {
+ public static Builder fromConfig(@NonNull Config configuration) {
+ return new Builder(MutableOptionsBundle.from(configuration));
+ }
+
+ /**
+ * Generates a Builder from another Config object
+ *
+ * @param configuration An immutable configuration to pre-populate this builder.
+ * @return The new Builder.
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static Builder fromConfig(@NonNull ImageCaptureConfig configuration) {
return new Builder(MutableOptionsBundle.from(configuration));
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
index 8a3b70b..8f92ad8 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
@@ -64,6 +64,7 @@
import androidx.camera.core.impl.CaptureConfig;
import androidx.camera.core.impl.CaptureProcessor;
import androidx.camera.core.impl.CaptureStage;
+import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.ConfigProvider;
import androidx.camera.core.impl.DeferrableSurface;
import androidx.camera.core.impl.ImageFormatConstants;
@@ -75,6 +76,7 @@
import androidx.camera.core.impl.PreviewConfig;
import androidx.camera.core.impl.SessionConfig;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.impl.utils.Threads;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.internal.CameraCaptureResultImageInfo;
@@ -377,7 +379,7 @@
// Either way, try updating session config and let createPipeline() sends a
// new SurfaceRequest.
if (getAttachedSurfaceResolution() != null) {
- updateConfigAndOutput(getCameraId(), (PreviewConfig) getUseCaseConfig(),
+ updateConfigAndOutput(getCameraId(), (PreviewConfig) getCurrentConfig(),
getAttachedSurfaceResolution());
notifyReset();
}
@@ -446,16 +448,23 @@
*
* @hide
*/
+ @RestrictTo(Scope.LIBRARY_GROUP)
@Override
@Nullable
- @RestrictTo(Scope.LIBRARY_GROUP)
- public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
- PreviewConfig defaults = CameraX.getDefaultUseCaseConfig(PreviewConfig.class);
- if (defaults != null) {
- return Builder.fromConfig(defaults);
- }
+ public UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory) {
+ return factory.getConfig(PreviewConfig.class);
+ }
- return null;
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+ return Preview.Builder.fromConfig(config);
}
/**
@@ -467,7 +476,7 @@
@RestrictTo(Scope.LIBRARY_GROUP)
@Override
public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder() {
- return Preview.Builder.fromConfig((PreviewConfig) getUseCaseConfig());
+ return Preview.Builder.fromConfig((PreviewConfig) getCurrentConfig());
}
/**
@@ -501,7 +510,7 @@
@NonNull
protected Size onSuggestedResolutionUpdated(@NonNull Size suggestedResolution) {
mSurfaceSize = suggestedResolution;
- updateConfigAndOutput(getCameraId(), (PreviewConfig) getUseCaseConfig(),
+ updateConfigAndOutput(getCameraId(), (PreviewConfig) getCurrentConfig(),
suggestedResolution);
return suggestedResolution;
}
@@ -597,8 +606,6 @@
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public static final class Defaults implements ConfigProvider<PreviewConfig> {
- private static final Size DEFAULT_MAX_RESOLUTION =
- CameraX.getSurfaceManager().getPreviewSize();
private static final int DEFAULT_SURFACE_OCCUPANCY_PRIORITY = 2;
private static final PreviewConfig DEFAULT_CONFIG;
@@ -606,7 +613,6 @@
static {
Builder builder =
new Builder()
- .setMaxResolution(DEFAULT_MAX_RESOLUTION)
.setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY);
DEFAULT_CONFIG = builder.getUseCaseConfig();
}
@@ -649,6 +655,18 @@
/**
* Generates a Builder from another Config object
+ * @return
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static Builder fromConfig(@NonNull Config configuration) {
+ return new Builder(MutableOptionsBundle.from(configuration));
+ }
+
+ /**
+ * Generates a Builder from another Config object
*
* @param configuration An immutable configuration to pre-populate this builder.
* @return The new Builder.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java b/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
index 8c50439..88ecd8b 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
@@ -16,8 +16,6 @@
package androidx.camera.core;
-import static androidx.camera.core.impl.ImageOutputConfig.OPTION_TARGET_ROTATION;
-
import android.annotation.SuppressLint;
import android.graphics.Rect;
import android.media.ImageReader;
@@ -33,11 +31,13 @@
import androidx.annotation.RestrictTo.Scope;
import androidx.camera.core.impl.CameraControlInternal;
import androidx.camera.core.impl.CameraInternal;
+import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.Config.Option;
import androidx.camera.core.impl.ImageOutputConfig;
-import androidx.camera.core.impl.MutableConfig;
+import androidx.camera.core.impl.MutableOptionsBundle;
import androidx.camera.core.impl.SessionConfig;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.internal.utils.UseCaseConfigUtil;
import androidx.core.util.Preconditions;
@@ -65,19 +65,8 @@
*/
private final Set<StateChangeCallback> mStateChangeCallbacks = new HashSet<>();
- /**
- * Store the initial {@link UseCaseConfig} used to create the use case.
- */
- private final UseCaseConfig<?> mInitialUseCaseConfig;
private final Object mCameraLock = new Object();
- /**
- * The default target rotation value is determined when the use case is created. Detaching
- * and attaching the use case won't change the use case's default target rotation value.
- */
- @ImageOutputConfig.RotationValue
- private final int mDefaultTargetRotation;
-
////////////////////////////////////////////////////////////////////////////////////////////
// [UseCase lifetime dynamic] - Dynamic variables which could change during anytime during
// the UseCase lifetime.
@@ -85,12 +74,25 @@
private State mState = State.INACTIVE;
- /** The target rotation setting set via {@link #setTargetRotationInternal(int)}. */
- @ImageOutputConfig.RotationValue
- private int mTargetRotation;
+ /** Extended config, applied on top of the app defined Config (mUseCaseConfig). */
+ @Nullable
+ private UseCaseConfig<?> mExtendedConfig;
+ /**
+ * Store the app defined {@link UseCaseConfig} used to create the use case.
+ */
+ @NonNull
private UseCaseConfig<?> mUseCaseConfig;
+ /**
+ * The currently used Config.
+ *
+ * <p> This is the combination of the extended Config, app provided Config, and camera
+ * implementation Config (with decreasing priority).
+ */
+ @NonNull
+ private UseCaseConfig<?> mCurrentConfig;
+
////////////////////////////////////////////////////////////////////////////////////////////
// [UseCase attached constant] - Is only valid when the UseCase is attached to a camera.
////////////////////////////////////////////////////////////////////////////////////////////
@@ -101,6 +103,13 @@
private Size mAttachedResolution;
/**
+ * The camera implementation provided Config. Its options has lowest priority and will be
+ * overwritten by any app defined or extended configs.
+ */
+ @Nullable
+ private UseCaseConfig<?> mCameraConfig;
+
+ /**
* The crop rect calculated at the time of binding based on {@link ViewPort}.
*/
@Nullable
@@ -119,131 +128,97 @@
/**
* Creates a named instance of the use case.
*
- * @param useCaseConfig the configuration object used for this use case
+ * @param currentConfig the configuration object used for this use case
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
- protected UseCase(@NonNull UseCaseConfig<?> useCaseConfig) {
- mInitialUseCaseConfig = useCaseConfig;
- mUseCaseConfig = useCaseConfig;
-
- // Determine the use case's target rotation value. If it has been provided in the
- // useCaseConfig, extract it. Otherwise, obtain it from the default config provider.
- if (useCaseConfig.containsOption(OPTION_TARGET_ROTATION)) {
- mDefaultTargetRotation = useCaseConfig.retrieveOption(OPTION_TARGET_ROTATION);
- } else {
- UseCaseConfig.Builder<?, ?, ?> defaultBuilder = getDefaultBuilder();
- mDefaultTargetRotation =
- defaultBuilder != null ? defaultBuilder.getUseCaseConfig().retrieveOption(
- OPTION_TARGET_ROTATION, Surface.ROTATION_0) : Surface.ROTATION_0;
- }
-
- mTargetRotation = mDefaultTargetRotation;
+ protected UseCase(@NonNull UseCaseConfig<?> currentConfig) {
+ mUseCaseConfig = currentConfig;
+ mCurrentConfig = currentConfig;
}
/**
- * Returns a use case configuration pre-populated with default configuration
- * options.
+ * Retrieve the default {@link UseCaseConfig} for the UseCase.
*
- * <p>This is used to generate a final configuration by combining the user-supplied
- * configuration with the default configuration. Subclasses can override this method to provide
- * the pre-populated builder. If <code>null</code> is returned, then the user-supplied
- * configuration will be used directly.
- *
- * @return A builder pre-populated with use case default options.
+ * @param factory the factory that contains the default UseCases.
+ * @return The UseCaseConfig or null if there is no default Config.
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
- public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
- return null;
- }
+ public abstract UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory);
/**
- * Updates the stored use case configuration.
+ * Create a {@link UseCaseConfig.Builder} for the UseCase.
*
- * <p>This configuration will be combined with the default configuration that is contained in
- * the pre-populated builder supplied by {@link #getDefaultBuilder}, if it exists and the
- * behavior of {@link #applyDefaults(UseCaseConfig, UseCaseConfig.Builder)} is not overridden.
- * Once this method returns, the combined use case configuration can be retrieved with
- * {@link #getUseCaseConfig()}.
- *
- * <p>This method alone will not make any changes to the {@link SessionConfig}, it is up to
- * the use case to decide when to modify the session configuration.
- *
- * @param useCaseConfig Configuration which will be applied on top of use case defaults, if a
- * default builder is provided by {@link #getDefaultBuilder}.
- * @throws IllegalStateException if this function is called when the UseCase is not attached
- * to a camera.
- * @hide
- */
- @RestrictTo(Scope.LIBRARY_GROUP)
- protected final void updateUseCaseConfig(@NonNull UseCaseConfig<?> useCaseConfig) {
- // updateUseCaseConfig() can only be called after the use case is attached to a camera
- // and then the settings will only be applied to the use case config. This is to make the
- // use case config static.
- CameraInternal camera = getCamera();
-
- if (camera == null) {
- throw new IllegalStateException("Disallow to call updateUseCaseConfig() before the "
- + "use case is attached to a camera.");
- }
-
- // Attempt to retrieve builder containing defaults for this use case's config
- UseCaseConfig.Builder<?, ?, ?> defaultBuilder = getDefaultBuilder();
-
- // Combine with default configuration.
- mUseCaseConfig = applyDefaults(useCaseConfig, defaultBuilder);
- }
-
- /**
- * Combines user-supplied configuration with use case default configuration.
- *
- * <p>Subclasses can override this method to
- * modify the behavior of combining user-supplied values and default values.
- *
- * @param userConfig The user-supplied configuration.
- * @param defaultConfigBuilder A builder containing use-case default values, or {@code null}
- * if no default values exist.
- * @return The configuration that will be used by this use case.
+ * @param config the Config to initialize the builder
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- public UseCaseConfig<?> applyDefaults(
- @NonNull UseCaseConfig<?> userConfig,
- @Nullable UseCaseConfig.Builder<?, ?, ?> defaultConfigBuilder) {
- if (defaultConfigBuilder == null) {
+ public abstract UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config);
+
+ /**
+ * Create a merged {@link UseCaseConfig} from the UseCase, camera, and an extended config.
+ *
+ * @param extendedConfig configs that take priority over the UseCase's default config
+ * @param cameraDefaultConfig configs that have lower priority than the UseCase's default.
+ * This Config comes from the camera implementation.
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public UseCaseConfig<?> mergeConfigs(
+ @Nullable UseCaseConfig<?> extendedConfig,
+ @Nullable UseCaseConfig<?> cameraDefaultConfig) {
+ if (extendedConfig == null && cameraDefaultConfig == null) {
// No default builder was retrieved, return config directly
- return userConfig;
+ return mUseCaseConfig;
}
- MutableConfig defaultMutableConfig = defaultConfigBuilder.getMutableConfig();
+ MutableOptionsBundle mergedConfig;
+
+ if (cameraDefaultConfig != null) {
+ mergedConfig = MutableOptionsBundle.from(cameraDefaultConfig);
+ } else {
+ mergedConfig = MutableOptionsBundle.create();
+ }
+
+ // If any options need special handling, this is the place to do it. For now we'll just copy
+ // over all options.
+ for (Option<?> opt : mUseCaseConfig.listOptions()) {
+ @SuppressWarnings("unchecked") // Options/values are being copied directly
+ Option<Object> objectOpt = (Option<Object>) opt;
+
+ mergedConfig.insertOption(objectOpt,
+ mUseCaseConfig.getOptionPriority(opt),
+ mUseCaseConfig.retrieveOption(objectOpt));
+ }
+
+ if (extendedConfig != null) {
+ // If any options need special handling, this is the place to do it. For now we'll
+ // just copy
+ // over all options.
+ for (Option<?> opt : extendedConfig.listOptions()) {
+ @SuppressWarnings("unchecked") // Options/values are being copied directly
+ Option<Object> objectOpt = (Option<Object>) opt;
+
+ mergedConfig.insertOption(objectOpt,
+ extendedConfig.getOptionPriority(opt),
+ extendedConfig.retrieveOption(objectOpt));
+ }
+ }
// If OPTION_TARGET_RESOLUTION has been set by the user, remove
// OPTION_TARGET_ASPECT_RATIO from defaultConfigBuilder because these two settings can be
// set at the same time.
- if (userConfig.containsOption(ImageOutputConfig.OPTION_TARGET_RESOLUTION)
- && defaultMutableConfig.containsOption(
+ if (mergedConfig.containsOption(ImageOutputConfig.OPTION_TARGET_RESOLUTION)
+ && mergedConfig.containsOption(
ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)) {
- defaultMutableConfig.removeOption(ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO);
+ mergedConfig.removeOption(ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO);
}
- // Overwrite the default config builder's target rotation value by the determined default
- // target rotation value of the use case.
- defaultMutableConfig.insertOption(OPTION_TARGET_ROTATION, mDefaultTargetRotation);
-
- // If any options need special handling, this is the place to do it. For now we'll just copy
- // over all options.
- for (Option<?> opt : userConfig.listOptions()) {
- @SuppressWarnings("unchecked") // Options/values are being copied directly
- Option<Object> objectOpt = (Option<Object>) opt;
-
- defaultMutableConfig.insertOption(objectOpt,
- userConfig.getOptionPriority(opt), userConfig.retrieveOption(objectOpt));
- }
-
- return defaultConfigBuilder.getUseCaseConfig();
+ return getUseCaseConfigBuilder(mergedConfig).getUseCaseConfig();
}
/**
@@ -258,19 +233,15 @@
@RestrictTo(Scope.LIBRARY_GROUP)
protected boolean setTargetRotationInternal(
@ImageOutputConfig.RotationValue int targetRotation) {
- ImageOutputConfig oldConfig = (ImageOutputConfig) getUseCaseConfig();
+ ImageOutputConfig oldConfig = (ImageOutputConfig) getCurrentConfig();
int oldRotation = oldConfig.getTargetRotation(ImageOutputConfig.INVALID_ROTATION);
if (oldRotation == ImageOutputConfig.INVALID_ROTATION || oldRotation != targetRotation) {
- // Camera is not null if the use case has been attached to a camera. Only calling
- // updateUseCaseConfig() when the use case has been attached to a camera. So that
- // some default config will be applied to the use case config.
- if (getCamera() != null) {
- UseCaseConfig.Builder<?, ?, ?> builder = getUseCaseConfigBuilder();
- UseCaseConfigUtil.updateTargetRotationAndRelatedConfigs(builder, targetRotation);
- updateUseCaseConfig(builder.getUseCaseConfig());
- }
+ UseCaseConfig.Builder<?, ?, ?> builder = getUseCaseConfigBuilder(mUseCaseConfig);
+ UseCaseConfigUtil.updateTargetRotationAndRelatedConfigs(builder, targetRotation);
+ mUseCaseConfig = builder.getUseCaseConfig();
- mTargetRotation = targetRotation;
+ mCurrentConfig = mergeConfigs(mExtendedConfig, mCameraConfig);
+
return true;
}
return false;
@@ -280,14 +251,13 @@
* Returns the rotation that the intended target resolution is expressed in.
*
* @return The rotation of the intended target.
- *
* @hide
*/
@SuppressLint("WrongConstant")
@RestrictTo(Scope.LIBRARY_GROUP)
@ImageOutputConfig.RotationValue
protected int getTargetRotationInternal() {
- return mTargetRotation;
+ return ((ImageOutputConfig) mCurrentConfig).getTargetRotation(Surface.ROTATION_0);
}
/**
@@ -298,7 +268,8 @@
@RestrictTo(Scope.LIBRARY_GROUP)
@IntRange(from = 0, to = 359)
protected int getRelativeRotation(@NonNull CameraInternal cameraInternal) {
- return cameraInternal.getCameraInfoInternal().getSensorRotationDegrees(mTargetRotation);
+ return cameraInternal.getCameraInfoInternal().getSensorRotationDegrees(
+ getTargetRotationInternal());
}
/**
@@ -442,7 +413,7 @@
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public String getName() {
- return mUseCaseConfig.getTargetName("<UnknownUseCase-" + this.hashCode() + ">");
+ return mCurrentConfig.getTargetName("<UnknownUseCase-" + this.hashCode() + ">");
}
/**
@@ -452,8 +423,9 @@
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
- public UseCaseConfig<?> getUseCaseConfig() {
- return mUseCaseConfig;
+ @NonNull
+ public UseCaseConfig<?> getCurrentConfig() {
+ return mCurrentConfig;
}
/**
@@ -535,18 +507,16 @@
*/
@SuppressLint("WrongConstant")
@RestrictTo(Scope.LIBRARY_GROUP)
- public void onAttach(@NonNull CameraInternal camera) {
+ public void onAttach(@NonNull CameraInternal camera, @NonNull UseCaseConfigFactory factory) {
synchronized (mCameraLock) {
mCamera = camera;
addStateChangeCallback(camera);
}
- updateUseCaseConfig(mUseCaseConfig);
+ mCameraConfig = getDefaultConfig(factory);
+ mCurrentConfig = mergeConfigs(mExtendedConfig, mCameraConfig);
- // Updates the user persistent target rotation setting to the use case config.
- setTargetRotationInternal(mTargetRotation);
-
- EventCallback eventCallback = mUseCaseConfig.getUseCaseEventCallback(null);
+ EventCallback eventCallback = mCurrentConfig.getUseCaseEventCallback(null);
if (eventCallback != null) {
eventCallback.onBind(camera.getCameraInfoInternal().getCameraId());
}
@@ -580,7 +550,7 @@
onDetached();
// Cleanup required for any type of UseCase
- EventCallback eventCallback = mUseCaseConfig.getUseCaseEventCallback(null);
+ EventCallback eventCallback = mCurrentConfig.getUseCaseEventCallback(null);
if (eventCallback != null) {
eventCallback.onUnbind();
}
@@ -596,7 +566,8 @@
// Resets the mUseCaseConfig to the initial status when the use case was created to make
// the use case reusable.
- mUseCaseConfig = mInitialUseCaseConfig;
+ mCurrentConfig = mUseCaseConfig;
+ mCameraConfig = null;
}
/**
@@ -673,7 +644,7 @@
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public int getImageFormat() {
- return mUseCaseConfig.getInputFormat();
+ return mCurrentConfig.getInputFormat();
}
enum State {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
index cdf1c21..eee4f7f 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
@@ -76,6 +76,7 @@
import androidx.annotation.UiThread;
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.core.impl.CaptureConfig;
+import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.ConfigProvider;
import androidx.camera.core.impl.DeferrableSurface;
import androidx.camera.core.impl.ImageOutputConfig;
@@ -86,6 +87,7 @@
import androidx.camera.core.impl.OptionsBundle;
import androidx.camera.core.impl.SessionConfig;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.camera.core.impl.VideoCaptureConfig;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.internal.ThreadConfig;
@@ -260,22 +262,16 @@
return format;
}
-
/**
* {@inheritDoc}
*
* @hide
*/
+ @RestrictTo(Scope.LIBRARY_GROUP)
@Override
@Nullable
- @RestrictTo(Scope.LIBRARY_GROUP)
- public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
- VideoCaptureConfig defaults = CameraX.getDefaultUseCaseConfig(VideoCaptureConfig.class);
- if (defaults != null) {
- return Builder.fromConfig(defaults);
- }
-
- return null;
+ public UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory) {
+ return factory.getConfig(VideoCaptureConfig.class);
}
/**
@@ -520,8 +516,20 @@
@NonNull
@RestrictTo(Scope.LIBRARY_GROUP)
@Override
+ public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+ return Builder.fromConfig(config);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder() {
- return Builder.fromConfig((VideoCaptureConfig) getUseCaseConfig());
+ return Builder.fromConfig(getCurrentConfig());
}
/**
@@ -581,7 +589,7 @@
@UiThread
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
void setupEncoder(@NonNull String cameraId, @NonNull Size resolution) {
- VideoCaptureConfig config = (VideoCaptureConfig) getUseCaseConfig();
+ VideoCaptureConfig config = (VideoCaptureConfig) getCurrentConfig();
// video encoder setup
mVideoEncoder.reset();
@@ -976,7 +984,7 @@
// In case no corresponding camcorder profile can be founded, * get default value from
// VideoCaptureConfig.
if (!isCamcorderProfileFound) {
- VideoCaptureConfig config = (VideoCaptureConfig) getUseCaseConfig();
+ VideoCaptureConfig config = (VideoCaptureConfig) getCurrentConfig();
mAudioChannelCount = config.getAudioChannelCount();
mAudioSampleRate = config.getAudioSampleRate();
mAudioBitRate = config.getAudioBitRate();
@@ -1199,6 +1207,20 @@
}
/**
+ * Generates a Builder from another Config object.
+ *
+ * @param configuration An immutable configuration to pre-populate this builder.
+ * @return The new Builder.
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ static Builder fromConfig(@NonNull Config configuration) {
+ return new Builder(MutableOptionsBundle.from(configuration));
+ }
+
+
+ /**
* Generates a Builder from another Config object
*
* @param configuration An immutable configuration to pre-populate this builder.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
index fd60409..3f39bf9 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
@@ -33,6 +33,7 @@
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.core.impl.SurfaceConfig;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import androidx.core.util.Preconditions;
import java.util.ArrayList;
@@ -56,6 +57,7 @@
private final CameraInternal mCameraInternal;
private final LinkedHashSet<CameraInternal> mCameraInternals;
private final CameraDeviceSurfaceManager mCameraDeviceSurfaceManager;
+ private final UseCaseConfigFactory mUseCaseConfigFactory;
private static final String TAG = "CameraUseCaseAdapter";
@@ -85,11 +87,13 @@
*/
public CameraUseCaseAdapter(@NonNull CameraInternal cameraInternal,
@NonNull LinkedHashSet<CameraInternal> cameras,
- @NonNull CameraDeviceSurfaceManager cameraDeviceSurfaceManager) {
+ @NonNull CameraDeviceSurfaceManager cameraDeviceSurfaceManager,
+ @NonNull UseCaseConfigFactory useCaseConfigFactory) {
mCameraInternal = cameraInternal;
mCameraInternals = new LinkedHashSet<>(cameras);
mId = new CameraId(mCameraInternals);
mCameraDeviceSurfaceManager = cameraDeviceSurfaceManager;
+ mUseCaseConfigFactory = useCaseConfigFactory;
}
/**
@@ -130,12 +134,6 @@
* <p> This does not take into account UseCases which are already attached to the camera.
*/
public void checkAttachUseCases(@NonNull List<UseCase> useCases) throws CameraException {
- // Only do resolution calculation if UseCases were bound
- if (!UseCaseOccupancy.checkUseCaseLimitNotExceeded(useCases)) {
- throw new CameraException("Attempting to bind too many ImageCapture or "
- + "VideoCapture instances");
- }
-
// If the UseCases exceed the resolutions then it will throw an exception
try {
calculateSuggestedResolutions(useCases, Collections.emptyList());
@@ -153,24 +151,16 @@
@UseExperimental(markerClass = androidx.camera.core.ExperimentalUseCaseGroup.class)
public void addUseCases(@NonNull Collection<UseCase> useCases) throws CameraException {
synchronized (mLock) {
- List<UseCase> useCaseListAfterUpdate = new ArrayList<>(mUseCases);
List<UseCase> newUseCases = new ArrayList<>();
for (UseCase useCase : useCases) {
if (mUseCases.contains(useCase)) {
Logger.d(TAG, "Attempting to attach already attached UseCase");
} else {
- useCaseListAfterUpdate.add(useCase);
newUseCases.add(useCase);
}
}
- // Only do resolution calculation if UseCases were bound
- if (!UseCaseOccupancy.checkUseCaseLimitNotExceeded(useCaseListAfterUpdate)) {
- throw new CameraException("Attempting to bind too many ImageCapture or "
- + "VideoCapture instances");
- }
-
Map<UseCase, Size> suggestedResolutionsMap;
try {
suggestedResolutionsMap =
@@ -198,7 +188,7 @@
// At this point the binding will succeed since all the calculations are done
// Do all attaching related work
for (UseCase useCase : newUseCases) {
- useCase.onAttach(mCameraInternal);
+ useCase.onAttach(mCameraInternal, mUseCaseConfigFactory);
useCase.updateSuggestedResolution(
Preconditions.checkNotNull(suggestedResolutionsMap.get(useCase)));
}
@@ -303,12 +293,11 @@
if (!newUseCases.isEmpty()) {
Map<UseCaseConfig<?>, UseCase> configToUseCaseMap = new HashMap<>();
for (UseCase useCase : newUseCases) {
- UseCaseConfig.Builder<?, ?, ?> defaultBuilder = useCase.getDefaultBuilder();
+ UseCaseConfig<?> defaultConfig =
+ useCase.getDefaultConfig(mUseCaseConfigFactory);
// Combine with default configuration.
- UseCaseConfig<?> combinedUseCaseConfig =
- useCase.applyDefaults(useCase.getUseCaseConfig(),
- defaultBuilder);
+ UseCaseConfig<?> combinedUseCaseConfig = useCase.mergeConfigs(null, defaultConfig);
configToUseCaseMap.put(combinedUseCaseConfig, useCase);
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/UseCaseOccupancy.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/UseCaseOccupancy.java
deleted file mode 100644
index 1790cd9..0000000
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/UseCaseOccupancy.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2020 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 androidx.camera.core.internal;
-
-import androidx.annotation.NonNull;
-import androidx.camera.core.ImageCapture;
-import androidx.camera.core.Logger;
-import androidx.camera.core.UseCase;
-import androidx.camera.core.VideoCapture;
-
-import java.util.List;
-
-/**
- * Checks to see if the number of specific {@link UseCase} exceeds the supported number.
- */
-public final class UseCaseOccupancy {
- private static final String TAG = "UseCaseOccupancy";
- private UseCaseOccupancy() {
- }
-
- /**
- * Check to see if CameraX supports running the set of use cases.
- *
- * @return true if the set of use cases is supported, otherwise false
- */
- public static boolean checkUseCaseLimitNotExceeded(
- @NonNull List<UseCase> useCases) {
- int imageCaptureCount = 0;
- int videoCaptureCount = 0;
-
- for (UseCase useCase : useCases) {
- if (useCase instanceof ImageCapture) {
- imageCaptureCount++;
- } else if (useCase instanceof VideoCapture) {
- videoCaptureCount++;
- }
- }
-
- if (imageCaptureCount > 1) {
- Logger.e(TAG, "Exceeded max simultaneously bound image capture use cases.");
- return false;
- }
-
- if (videoCaptureCount > 1) {
- Logger.e(TAG, "Exceeded max simultaneously bound video capture use cases.");
- return false;
- }
-
- return true;
- }
-}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java
index c63c9df..c7d011a 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java
@@ -45,6 +45,22 @@
}
/**
+ * Converts a {@link Size} to an float array of vertexes.
+ */
+ @NonNull
+ public static float[] sizeToVertexes(@NonNull Size size) {
+ return new float[]{0, 0, size.getWidth(), 0, size.getWidth(), size.getHeight(), 0,
+ size.getHeight()};
+ }
+
+ /**
+ * Returns the min value.
+ */
+ public static float min(float value1, float value2, float value3, float value4) {
+ return Math.min(Math.min(value1, value2), Math.min(value3, value4));
+ }
+
+ /**
* Rotates aspect ratio based on rotation degrees.
*/
@NonNull
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java b/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
index 31d8cee..ff41aef 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
@@ -30,6 +30,7 @@
import android.view.Surface;
import androidx.camera.core.impl.CameraFactory;
+import androidx.camera.core.impl.CameraInternal;
import androidx.camera.core.impl.TagBundle;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.internal.CameraUseCaseAdapter;
@@ -65,7 +66,7 @@
@MediumTest
@RunWith(RobolectricTestRunner.class)
@DoNotInstrument
-@Config(minSdk = Build.VERSION_CODES.LOLLIPOP, shadows = {ShadowCameraX.class})
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
public class ImageAnalysisTest {
private static final int QUEUE_DEPTH = 8;
@@ -103,10 +104,12 @@
mTagBundle = TagBundle.create(new Pair<>("FakeCaptureStageId", IMAGE_TAG));
+ CameraInternal camera = new FakeCamera();
+
CameraFactory.Provider cameraFactoryProvider = (ignored1, ignored2) -> {
FakeCameraFactory cameraFactory = new FakeCameraFactory();
- cameraFactory.insertDefaultBackCamera(ShadowCameraX.DEFAULT_CAMERA_ID,
- () -> new FakeCamera(ShadowCameraX.DEFAULT_CAMERA_ID));
+ cameraFactory.insertDefaultBackCamera(camera.getCameraInfoInternal().getCameraId(),
+ () -> camera);
return cameraFactory;
};
CameraXConfig cameraXConfig = CameraXConfig.Builder.fromConfig(
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureTest.kt
index b38856c..d00ee97 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureTest.kt
@@ -81,7 +81,7 @@
@MediumTest
@RunWith(RobolectricTestRunner::class)
@DoNotInstrument
-@Config(minSdk = Build.VERSION_CODES.LOLLIPOP, shadows = [ShadowCameraX::class])
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
class ImageCaptureTest {
private lateinit var callbackHandler: Handler
@@ -102,11 +102,13 @@
@Before
@Throws(ExecutionException::class, InterruptedException::class)
fun setUp() {
+ val camera = FakeCamera()
+
val cameraFactoryProvider =
CameraFactory.Provider { _: Context?, _: CameraThreadConfig? ->
val cameraFactory = FakeCameraFactory()
- cameraFactory.insertDefaultBackCamera(ShadowCameraX.DEFAULT_CAMERA_ID) {
- FakeCamera(ShadowCameraX.DEFAULT_CAMERA_ID)
+ cameraFactory.insertDefaultBackCamera(camera.cameraInfoInternal.cameraId) {
+ camera
}
cameraFactory
}
@@ -171,7 +173,8 @@
fakeImageReaderProxy?.triggerImageAvailable(TagBundle.create(Pair("TagBundleKey", 0)), 0)
flushHandler(callbackHandler)
cameraUseCaseAdapter.removeUseCases(
- Collections.singleton(imageCapture) as Collection<UseCase>)
+ Collections.singleton(imageCapture) as Collection<UseCase>
+ )
// Assert.
// The captured image should still be valid even if the ImageCapture has been unbound. It
@@ -361,8 +364,11 @@
.setSessionOptionUnpacker(sessionOptionUnpacker)
.build()
- cameraUseCaseAdapter = CameraUtil.createCameraUseCaseAdapter(ApplicationProvider
- .getApplicationContext<Context>(), CameraSelector.DEFAULT_BACK_CAMERA)
+ cameraUseCaseAdapter = CameraUtil.createCameraUseCaseAdapter(
+ ApplicationProvider
+ .getApplicationContext<Context>(),
+ CameraSelector.DEFAULT_BACK_CAMERA
+ )
cameraUseCaseAdapter.setViewPort(viewPort)
cameraUseCaseAdapter.addUseCases(Collections.singleton<UseCase>(imageCapture))
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
index 5483966..5471a14 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
@@ -59,21 +59,22 @@
@RunWith(RobolectricTestRunner::class)
@DoNotInstrument
@Config(
- minSdk = Build.VERSION_CODES.LOLLIPOP, shadows = [ShadowCameraX::class]
+ minSdk = Build.VERSION_CODES.LOLLIPOP
)
class PreviewTest {
-
var cameraUseCaseAdapter: CameraUseCaseAdapter? = null
@Before
@Throws(ExecutionException::class, InterruptedException::class)
fun setUp() {
+ val camera = FakeCamera()
+
val cameraFactoryProvider =
CameraFactory.Provider { _: Context?, _: CameraThreadConfig? ->
val cameraFactory = FakeCameraFactory()
cameraFactory.insertDefaultBackCamera(
- ShadowCameraX.DEFAULT_CAMERA_ID
- ) { FakeCamera(ShadowCameraX.DEFAULT_CAMERA_ID) }
+ camera.cameraInfoInternal.cameraId
+ ) { camera }
cameraFactory
}
val cameraXConfig = CameraXConfig.Builder.fromConfig(
@@ -100,8 +101,10 @@
)
// The expected value is based on fitting the 1:1 view port into a rect with the size of
// FakeCameraDeviceSurfaceManager.MAX_OUTPUT_SIZE.
- val expectedPadding = (FakeCameraDeviceSurfaceManager.MAX_OUTPUT_SIZE.width -
- FakeCameraDeviceSurfaceManager.MAX_OUTPUT_SIZE.height) / 2
+ val expectedPadding = (
+ FakeCameraDeviceSurfaceManager.MAX_OUTPUT_SIZE.width -
+ FakeCameraDeviceSurfaceManager.MAX_OUTPUT_SIZE.height
+ ) / 2
assertThat(transformationInfo.cropRect).isEqualTo(
Rect(
expectedPadding,
@@ -174,7 +177,8 @@
CameraXExecutors.directExecutor(),
SurfaceRequest.TransformationInfoListener {
receivedTransformationInfo = it
- })
+ }
+ )
}
shadowOf(getMainLooper()).idle()
assertThat(receivedTransformationInfo!!.cropRect.getAspectRatio()).isEqualTo(rational1)
@@ -213,7 +217,8 @@
CameraXExecutors.directExecutor(),
SurfaceRequest.TransformationInfoListener {
receivedTransformationInfo = it
- })
+ }
+ )
}
shadowOf(getMainLooper()).idle()
assertThat(receivedTransformationInfo!!.targetRotation).isEqualTo(Surface.ROTATION_0)
@@ -237,7 +242,8 @@
.build()
val cameraUseCaseAdapter = CameraUtil.createCameraUseCaseAdapter(
ApplicationProvider
- .getApplicationContext(), TEST_CAMERA_SELECTOR
+ .getApplicationContext(),
+ TEST_CAMERA_SELECTOR
)
cameraUseCaseAdapter.addUseCases(Collections.singleton<UseCase>(preview))
@@ -252,7 +258,8 @@
CameraXExecutors.directExecutor(),
SurfaceRequest.TransformationInfoListener {
receivedTransformationInfo = it
- })
+ }
+ )
receivedSurfaceRequest = request
}
shadowOf(getMainLooper()).idle()
@@ -267,7 +274,8 @@
CameraXExecutors.directExecutor(),
SurfaceRequest.TransformationInfoListener {
receivedTransformationInfo = it
- })
+ }
+ )
receivedSurfaceRequest = request
}
shadowOf(getMainLooper()).idle()
@@ -287,7 +295,8 @@
.build()
cameraUseCaseAdapter = CameraUtil.createCameraUseCaseAdapter(
ApplicationProvider
- .getApplicationContext(), TEST_CAMERA_SELECTOR
+ .getApplicationContext(),
+ TEST_CAMERA_SELECTOR
)
// Attach
cameraUseCaseAdapter!!.addUseCases(Collections.singleton<UseCase>(preview))
@@ -317,12 +326,12 @@
}
private fun bindToLifecycleAndGetTransformationInfo(viewPort: ViewPort?):
- SurfaceRequest.TransformationInfo {
- return bindToLifecycleAndGetResult(viewPort).second
- }
+ SurfaceRequest.TransformationInfo {
+ return bindToLifecycleAndGetResult(viewPort).second
+ }
private fun bindToLifecycleAndGetResult(viewPort: ViewPort?): Pair<SurfaceRequest,
- SurfaceRequest.TransformationInfo> {
+ SurfaceRequest.TransformationInfo> {
// Arrange.
val sessionOptionUnpacker =
{ _: UseCaseConfig<*>?, _: SessionConfig.Builder? -> }
@@ -337,7 +346,8 @@
CameraXExecutors.directExecutor(),
SurfaceRequest.TransformationInfoListener {
transformationInfo = it
- })
+ }
+ )
surfaceRequest = request
}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java b/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java
deleted file mode 100644
index 50189ad6..0000000
--- a/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2019 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 androidx.camera.core;
-
-import androidx.annotation.Nullable;
-import androidx.camera.core.impl.CameraDeviceSurfaceManager;
-import androidx.camera.core.impl.ImageAnalysisConfig;
-import androidx.camera.core.impl.ImageCaptureConfig;
-import androidx.camera.core.impl.PreviewConfig;
-import androidx.camera.core.impl.UseCaseConfig;
-import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
-import androidx.camera.testing.fakes.FakeCameraInfoInternal;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-/**
- * A Robolectric shadow of {@link CameraX}.
- */
-@Implements(CameraX.class)
-public class ShadowCameraX {
- public static final String DEFAULT_CAMERA_ID = "0";
-
- private static final UseCaseConfig<ImageAnalysis> DEFAULT_IMAGE_ANALYSIS_CONFIG =
- new ImageAnalysis.Builder().setSessionOptionUnpacker(
- (config, builder) -> {
- }).getUseCaseConfig();
-
- private static final UseCaseConfig<Preview> DEFAULT_PREVIEW_CONFIG =
- new Preview.Builder().setSessionOptionUnpacker(
- (config, builder) -> {
- }).getUseCaseConfig();
-
- private static final UseCaseConfig<ImageCapture> DEFAULT_IMAGE_CAPTURE_CONFIG =
- new ImageCapture.Builder().setSessionOptionUnpacker(
- (config, builder) -> {
- }).getUseCaseConfig();
-
- private static final CameraInfo DEFAULT_CAMERA_INFO = new FakeCameraInfoInternal();
-
- private static final CameraDeviceSurfaceManager DEFAULT_DEVICE_SURFACE_MANAGER =
- new FakeCameraDeviceSurfaceManager();
-
- /**
- * Shadow of {@link CameraX#getCameraInfo(String)}.
- */
- @Implementation
- public static CameraInfo getCameraInfo(String cameraId) {
- return DEFAULT_CAMERA_INFO;
- }
-
- /**
- * Shadow of {@link CameraX#getDefaultUseCaseConfig(Class, CameraInfo)}.
- */
- @SuppressWarnings("unchecked")
- @Implementation
- public static <C extends UseCaseConfig<?>> C getDefaultUseCaseConfig(Class<C> configType,
- @Nullable CameraInfo cameraInfo) {
- if (configType.equals(PreviewConfig.class)) {
- return (C) DEFAULT_PREVIEW_CONFIG;
- } else if (configType.equals(ImageAnalysisConfig.class)) {
- return (C) DEFAULT_IMAGE_ANALYSIS_CONFIG;
- } else if (configType.equals(ImageCaptureConfig.class)) {
- return (C) DEFAULT_IMAGE_CAPTURE_CONFIG;
- }
- throw new UnsupportedOperationException(
- "Shadow UseCase config not implemented: " + configType);
- }
-
- /**
- * Shadow of {@link CameraX#getSurfaceManager()}.
- */
- @Implementation
- public static CameraDeviceSurfaceManager getSurfaceManager() {
- return DEFAULT_DEVICE_SURFACE_MANAGER;
- }
-}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/VideoCaptureTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/VideoCaptureTest.kt
index 2f4340f..e2ce334 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/VideoCaptureTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/VideoCaptureTest.kt
@@ -46,18 +46,18 @@
@RunWith(RobolectricTestRunner::class)
@DoNotInstrument
@Config(
- minSdk = Build.VERSION_CODES.LOLLIPOP, shadows = [ShadowCameraX::class]
+ minSdk = Build.VERSION_CODES.LOLLIPOP
)
class VideoCaptureTest {
@Before
fun setUp() {
+ val camera = FakeCamera()
+
val cameraFactoryProvider =
CameraFactory.Provider { _: Context?, _: CameraThreadConfig? ->
val cameraFactory = FakeCameraFactory()
- cameraFactory.insertDefaultBackCamera(ShadowCameraX.DEFAULT_CAMERA_ID) {
- FakeCamera(
- ShadowCameraX.DEFAULT_CAMERA_ID
- )
+ cameraFactory.insertDefaultBackCamera(camera.cameraInfoInternal.cameraId) {
+ camera
}
cameraFactory
}
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsTest.kt
index b5557095..32a6dc8 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsTest.kt
@@ -96,7 +96,7 @@
assertThat(
ExtensionsManager.isExtensionAvailable(mEffectMode, mLensFacing) ==
- mExtensions.isExtensionAvailable(camera, mExtensionMode)
+ mExtensions.isExtensionAvailable(camera, mExtensionMode)
).isTrue()
}
}
\ No newline at end of file
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java
index 7c87555..62b0651 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java
@@ -179,7 +179,7 @@
}
for (UseCase useCase : activeUseCases) {
- EffectMode previewExtenderMode = useCase.getUseCaseConfig().retrieveOption(
+ EffectMode previewExtenderMode = useCase.getCurrentConfig().retrieveOption(
PreviewExtender.OPTION_PREVIEW_EXTENDER_MODE, null);
if (effectMode == previewExtenderMode) {
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java
index 8ba37ca..5c493f8b 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java
@@ -185,7 +185,7 @@
}
for (UseCase useCase : activeUseCases) {
- EffectMode imageCaptureExtenderMode = useCase.getUseCaseConfig().retrieveOption(
+ EffectMode imageCaptureExtenderMode = useCase.getCurrentConfig().retrieveOption(
ImageCaptureExtender.OPTION_IMAGE_CAPTURE_EXTENDER_MODE, null);
if (effectMode == imageCaptureExtenderMode) {
diff --git a/camera/camera-lifecycle/api/1.0.0-beta10.txt b/camera/camera-lifecycle/api/1.0.0-beta10.txt
new file mode 100644
index 0000000..88187bc6
--- /dev/null
+++ b/camera/camera-lifecycle/api/1.0.0-beta10.txt
@@ -0,0 +1,14 @@
+// Signature format: 3.0
+package androidx.camera.lifecycle {
+
+ public final class ProcessCameraProvider {
+ method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method @MainThread public void unbind(androidx.camera.core.UseCase!...);
+ method @MainThread public void unbindAll();
+ }
+
+}
+
diff --git a/camera/camera-lifecycle/api/public_plus_experimental_1.0.0-beta10.txt b/camera/camera-lifecycle/api/public_plus_experimental_1.0.0-beta10.txt
new file mode 100644
index 0000000..d317ea5
--- /dev/null
+++ b/camera/camera-lifecycle/api/public_plus_experimental_1.0.0-beta10.txt
@@ -0,0 +1,22 @@
+// Signature format: 3.0
+package androidx.camera.lifecycle {
+
+ @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCameraProviderConfiguration {
+ }
+
+ @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalUseCaseGroupLifecycle {
+ }
+
+ public final class ProcessCameraProvider {
+ method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method @MainThread @androidx.camera.lifecycle.ExperimentalUseCaseGroupLifecycle public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCaseGroup);
+ method @androidx.camera.lifecycle.ExperimentalCameraProviderConfiguration public static void configureInstance(androidx.camera.core.CameraXConfig);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method @MainThread public void unbind(androidx.camera.core.UseCase!...);
+ method @MainThread public void unbindAll();
+ }
+
+}
+
diff --git a/camera/camera-lifecycle/api/res-1.0.0-beta10.txt b/camera/camera-lifecycle/api/res-1.0.0-beta10.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-lifecycle/api/res-1.0.0-beta10.txt
diff --git a/camera/camera-lifecycle/api/restricted_1.0.0-beta10.txt b/camera/camera-lifecycle/api/restricted_1.0.0-beta10.txt
new file mode 100644
index 0000000..88187bc6
--- /dev/null
+++ b/camera/camera-lifecycle/api/restricted_1.0.0-beta10.txt
@@ -0,0 +1,14 @@
+// Signature format: 3.0
+package androidx.camera.lifecycle {
+
+ public final class ProcessCameraProvider {
+ method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method @MainThread public void unbind(androidx.camera.core.UseCase!...);
+ method @MainThread public void unbindAll();
+ }
+
+}
+
diff --git a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java
index e2b5492..cb7e298 100644
--- a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java
+++ b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java
@@ -24,6 +24,7 @@
import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
import androidx.camera.testing.fakes.FakeLifecycleOwner;
import androidx.camera.testing.fakes.FakeUseCase;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
import androidx.lifecycle.LifecycleOwner;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -56,7 +57,8 @@
mCameraSet = new LinkedHashSet<>(Collections.singleton(camera));
mCameraUseCaseAdapter = new CameraUseCaseAdapter(camera,
mCameraSet,
- new FakeCameraDeviceSurfaceManager());
+ new FakeCameraDeviceSurfaceManager(),
+ new FakeUseCaseConfigFactory());
}
@Test(expected = IllegalArgumentException.class)
@@ -442,6 +444,7 @@
CameraInternal fakeCamera = new FakeCamera(cameraId);
return new CameraUseCaseAdapter(fakeCamera,
new LinkedHashSet<>(Collections.singleton(fakeCamera)),
- new FakeCameraDeviceSurfaceManager());
+ new FakeCameraDeviceSurfaceManager(),
+ new FakeUseCaseConfigFactory());
}
}
diff --git a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraTest.java b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraTest.java
index d5b46dd..db47919 100644
--- a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraTest.java
+++ b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraTest.java
@@ -23,6 +23,7 @@
import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
import androidx.camera.testing.fakes.FakeLifecycleOwner;
import androidx.camera.testing.fakes.FakeUseCase;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -48,7 +49,8 @@
mFakeCamera = new FakeCamera();
mCameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
new LinkedHashSet<>(Collections.singleton(mFakeCamera)),
- new FakeCameraDeviceSurfaceManager());
+ new FakeCameraDeviceSurfaceManager(),
+ new FakeUseCaseConfigFactory());
mFakeUseCase = new FakeUseCase();
}
diff --git a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt
index 6c5cc189..00497d0 100644
--- a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt
+++ b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt
@@ -312,12 +312,16 @@
provider = ProcessCameraProvider.getInstance(context).await()
val useCase0 = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
- val camera0 = provider.bindToLifecycle(lifecycleOwner0,
- CameraSelector.DEFAULT_BACK_CAMERA, useCase0)
+ val camera0 = provider.bindToLifecycle(
+ lifecycleOwner0,
+ CameraSelector.DEFAULT_BACK_CAMERA, useCase0
+ )
val useCase1 = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
- val camera1 = provider.bindToLifecycle(lifecycleOwner1,
- CameraSelector.DEFAULT_BACK_CAMERA, useCase1)
+ val camera1 = provider.bindToLifecycle(
+ lifecycleOwner1,
+ CameraSelector.DEFAULT_BACK_CAMERA, useCase1
+ )
assertThat(camera0).isNotEqualTo(camera1)
}
@@ -347,11 +351,18 @@
val useCase0 = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
val useCase1 = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
- val camera0 = provider.bindToLifecycle(lifecycleOwner0, CameraSelector
- .DEFAULT_BACK_CAMERA, useCase0)
- val camera1 = provider.bindToLifecycle(lifecycleOwner0, CameraSelector
- .DEFAULT_BACK_CAMERA,
- useCase1)
+ val camera0 = provider.bindToLifecycle(
+ lifecycleOwner0,
+ CameraSelector
+ .DEFAULT_BACK_CAMERA,
+ useCase0
+ )
+ val camera1 = provider.bindToLifecycle(
+ lifecycleOwner0,
+ CameraSelector
+ .DEFAULT_BACK_CAMERA,
+ useCase1
+ )
assertThat(camera0).isSameInstanceAs(camera1)
}
@@ -389,11 +400,19 @@
val useCase0 = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
val useCase1 = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
- val camera0 = provider.bindToLifecycle(lifecycleOwner0, CameraSelector
- .DEFAULT_BACK_CAMERA, useCase0)
+ val camera0 = provider.bindToLifecycle(
+ lifecycleOwner0,
+ CameraSelector
+ .DEFAULT_BACK_CAMERA,
+ useCase0
+ )
- val camera1 = provider.bindToLifecycle(lifecycleOwner1, CameraSelector
- .DEFAULT_FRONT_CAMERA, useCase1)
+ val camera1 = provider.bindToLifecycle(
+ lifecycleOwner1,
+ CameraSelector
+ .DEFAULT_FRONT_CAMERA,
+ useCase1
+ )
assertThat(camera0).isNotEqualTo(camera1)
}
@@ -450,7 +469,7 @@
provider = ProcessCameraProvider.getInstance(context).await()
val camera: LifecycleCamera =
provider.bindToLifecycle(lifecycleOwner0, CameraSelector.DEFAULT_BACK_CAMERA) as
- LifecycleCamera
+ LifecycleCamera
lifecycleOwner0.startAndResume()
assertThat(camera.isActive).isFalse()
}
@@ -464,7 +483,7 @@
lifecycleOwner0.startAndResume()
val camera: LifecycleCamera =
provider.bindToLifecycle(lifecycleOwner0, CameraSelector.DEFAULT_BACK_CAMERA) as
- LifecycleCamera
+ LifecycleCamera
assertThat(camera.isActive).isFalse()
}
}
@@ -539,7 +558,7 @@
}
private class TestAppContextWrapper(base: Context, val app: Application? = null) : ContextWrapper
- (base) {
+(base) {
val testResources = TestResources(base.resources)
@@ -565,7 +584,8 @@
@Suppress("DEPRECATION")
private class TestResources(base: Resources) : Resources(
- base.assets, base.displayMetrics, base
+ base.assets, base.displayMetrics,
+ base
.configuration
) {
diff --git a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
index 8312f2c..79ff401 100644
--- a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
+++ b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
@@ -375,7 +375,7 @@
CameraSelector.Builder.fromSelector(cameraSelector);
// Append the camera filter required internally if there's any.
for (UseCase useCase : useCases) {
- CameraSelector selector = useCase.getUseCaseConfig().getCameraSelector(null);
+ CameraSelector selector = useCase.getCurrentConfig().getCameraSelector(null);
if (selector != null) {
for (CameraFilter filter : selector.getCameraFilterSet()) {
selectorBuilder.addCameraFilter(filter);
@@ -414,7 +414,8 @@
mLifecycleCameraRepository.createLifecycleCamera(lifecycleOwner,
new CameraUseCaseAdapter(cameraInternals.iterator().next(),
cameraInternals,
- mCameraX.getCameraDeviceSurfaceManager()));
+ mCameraX.getCameraDeviceSurfaceManager(),
+ mCameraX.getDefaultConfigFactory()));
}
if (useCases.length == 0) {
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java b/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java
index 116a462..0c2b9e4 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java
@@ -283,7 +283,7 @@
LinkedHashSet<CameraInternal> cameras =
cameraSelector.filter(cameraX.getCameraRepository().getCameras());
return new CameraUseCaseAdapter(cameras.iterator().next(), cameras,
- cameraX.getCameraDeviceSurfaceManager());
+ cameraX.getCameraDeviceSurfaceManager(), cameraX.getDefaultConfigFactory());
} catch (ExecutionException | InterruptedException | TimeoutException e) {
throw new RuntimeException("Unable to retrieve CameraX instance");
}
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/Configs.java b/camera/camera-testing/src/main/java/androidx/camera/testing/Configs.java
index 4800728..b6d69bb 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/Configs.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/Configs.java
@@ -19,6 +19,7 @@
import androidx.annotation.NonNull;
import androidx.camera.core.UseCase;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
import java.util.HashMap;
import java.util.List;
@@ -31,15 +32,13 @@
/** Return a map that associates UseCases to UseCaseConfigs with default settings. */
@NonNull
public static Map<UseCase, UseCaseConfig<?>> useCaseConfigMapWithDefaultSettingsFromUseCaseList(
- @NonNull List<UseCase> useCases) {
+ @NonNull List<UseCase> useCases, @NonNull UseCaseConfigFactory useCaseConfigFactory) {
Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap = new HashMap<>();
for (UseCase useCase : useCases) {
- UseCaseConfig.Builder<?, ?, ?> defaultBuilder = useCase.getDefaultBuilder();
-
// Combine with default configuration.
- UseCaseConfig<?> combinedUseCaseConfig = useCase.applyDefaults(
- useCase.getUseCaseConfig(), defaultBuilder);
+ UseCaseConfig<?> combinedUseCaseConfig = useCase.mergeConfigs(null,
+ useCase.getDefaultConfig(useCaseConfigFactory));
useCaseToConfigMap.put(useCase, combinedUseCaseConfig);
}
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java b/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java
index 9a23aed..e2f4693 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java
@@ -133,7 +133,7 @@
LinkedHashSet<CameraInternal> cameras =
cameraSelector.filter(cameraX.getCameraRepository().getCameras());
mCameraUseCaseAdapter = new CameraUseCaseAdapter(cameras.iterator().next(), cameras,
- cameraX.getCameraDeviceSurfaceManager());
+ cameraX.getCameraDeviceSurfaceManager(), cameraX.getDefaultConfigFactory());
mCameraUseCaseAdapter.addUseCases(Collections.singleton(mPreview));
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
index a797434..b697234 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
@@ -20,9 +20,11 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
import androidx.camera.core.UseCase;
-import androidx.camera.core.impl.SessionConfig;
+import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
/**
* A fake {@link UseCase}.
@@ -44,16 +46,31 @@
this(new FakeUseCaseConfig.Builder().getUseCaseConfig());
}
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Override
+ public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+ return new FakeUseCaseConfig.Builder(config)
+ .setSessionOptionUnpacker((useCaseConfig, sessionConfigBuilder) -> { });
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
@Nullable
- public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
- return new FakeUseCaseConfig.Builder()
- .setSessionOptionUnpacker(new SessionConfig.OptionUnpacker() {
- @Override
- public void unpack(@NonNull UseCaseConfig<?> useCaseConfig,
- @NonNull SessionConfig.Builder sessionConfigBuilder) {
- }
- });
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @Override
+ public UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory) {
+ return new FakeUseCaseConfig.Builder(getCurrentConfig())
+ .setSessionOptionUnpacker((useCaseConfig, sessionConfigBuilder) -> {
+ }).getUseCaseConfig();
}
@Override
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
index 3d2db75..7759f10 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
@@ -68,6 +68,11 @@
setTargetClass(FakeUseCase.class);
}
+ public Builder(@NonNull Config config) {
+ mOptionsBundle = MutableOptionsBundle.from(config);
+ setTargetClass(FakeUseCase.class);
+ }
+
@Override
@NonNull
public MutableConfig getMutableConfig() {
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfigFactory.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfigFactory.java
new file mode 100644
index 0000000..1cfb60a
--- /dev/null
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfigFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 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 androidx.camera.testing.fakes;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
+
+/**
+ * A fake implementation of {@link UseCaseConfigFactory}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class FakeUseCaseConfigFactory implements UseCaseConfigFactory {
+ @Nullable
+ @Override
+ public <C extends UseCaseConfig<?>> C getConfig(@NonNull Class<C> configType) {
+ return null;
+ }
+}
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewTransformationDeviceTest.kt b/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewTransformationDeviceTest.kt
index 7605453..e32f258 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewTransformationDeviceTest.kt
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewTransformationDeviceTest.kt
@@ -187,7 +187,8 @@
SurfaceRequest.TransformationInfo.of(
CROP_RECT,
90, Surface.ROTATION_90
- ), SURFACE_SIZE
+ ),
+ SURFACE_SIZE
)
// Act.
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/AccelerometerRotationListener.java b/camera/camera-view/src/main/java/androidx/camera/view/AccelerometerRotationListener.java
new file mode 100644
index 0000000..b5cf3b5
--- /dev/null
+++ b/camera/camera-view/src/main/java/androidx/camera/view/AccelerometerRotationListener.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 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 androidx.camera.view;
+
+import android.content.Context;
+import android.view.OrientationEventListener;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+
+/**
+ * Listens to accelerometer reading and converts the orientation degrees to {@link Surface}
+ * rotation.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public abstract class AccelerometerRotationListener extends OrientationEventListener {
+
+ public static final int INVALID_SURFACE_ROTATION = -1;
+
+ private int mRotation = INVALID_SURFACE_ROTATION;
+
+ public AccelerometerRotationListener(@NonNull Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onOrientationChanged(int orientation) {
+ if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
+ // Short-circuit if orientation is unknown. Unknown rotation can't be handled so it
+ // shouldn't be sent.
+ return;
+ }
+
+ int newRotation;
+ if (orientation >= 315 || orientation < 45) {
+ newRotation = Surface.ROTATION_0;
+ } else if (orientation >= 225) {
+ newRotation = Surface.ROTATION_90;
+ } else if (orientation >= 135) {
+ newRotation = Surface.ROTATION_180;
+ } else {
+ newRotation = Surface.ROTATION_270;
+ }
+ if (mRotation != newRotation) {
+ mRotation = newRotation;
+ onRotationChanged(newRotation);
+ }
+ }
+
+ /**
+ * Invoked when rotation changes.
+ *
+ * <p> The output rotation is defined as the UI Surface rotation, or what the Surface rotation
+ * should be if the app's orientation is not locked.
+ */
+ public abstract void onRotationChanged(int rotation);
+}
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
index 1d97dfb..4067a55 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
@@ -16,8 +16,14 @@
package androidx.camera.view;
+import static androidx.camera.view.AccelerometerRotationListener.INVALID_SURFACE_ROTATION;
+
import android.annotation.SuppressLint;
import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.Display;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
@@ -39,6 +45,7 @@
import androidx.camera.core.UseCase;
import androidx.camera.core.UseCaseGroup;
import androidx.camera.core.VideoCapture;
+import androidx.camera.core.ViewPort;
import androidx.camera.core.ZoomState;
import androidx.camera.core.impl.utils.Threads;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
@@ -78,11 +85,6 @@
@Nullable
Preview mPreview;
- // SurfaceProvider form the latest attachPreviewSurface() call.
- // Synthetic access
- @SuppressWarnings("WeakerAccess")
- Preview.SurfaceProvider mSurfaceProvider;
-
// Synthetic access
@SuppressWarnings("WeakerAccess")
@Nullable
@@ -120,16 +122,46 @@
@Nullable
ProcessCameraProvider mCameraProvider;
+
+ // Synthetic access
+ @SuppressWarnings("WeakerAccess")
+ @Nullable
+ ViewPort mViewPort;
+
+ // Synthetic access
+ @SuppressWarnings("WeakerAccess")
+ @Nullable
+ Preview.SurfaceProvider mSurfaceProvider;
+
+ // Synthetic access
+ @SuppressWarnings("WeakerAccess")
+ @Nullable
+ Display mPreviewDisplay;
+
+ @NonNull
+ private final AccelerometerRotationListener mAccelerometerRotationListener;
+
+ @Nullable
+ private final DisplayChangeListener mDisplayChangeListener;
+
+ // Synthetic access
+ @SuppressWarnings("WeakerAccess")
+ int mAccelerometerRotation = INVALID_SURFACE_ROTATION;
+ int mDisplayRotation = INVALID_SURFACE_ROTATION;
+
private boolean mPinchToZoomEnabled = true;
private boolean mTapToFocusEnabled = true;
private final ForwardingLiveData<ZoomState> mZoomState = new ForwardingLiveData<>();
private final ForwardingLiveData<Integer> mTorchState = new ForwardingLiveData<>();
+ private final Context mAppContext;
+
CameraController(@NonNull Context context) {
+ mAppContext = context.getApplicationContext();
// Wait for camera to be initialized before binding use cases.
Futures.addCallback(
- ProcessCameraProvider.getInstance(context),
+ ProcessCameraProvider.getInstance(mAppContext),
new FutureCallback<ProcessCameraProvider>() {
@SuppressLint("MissingPermission")
@@ -141,6 +173,8 @@
mFlashMode).build();
mVideoCapture = new VideoCapture.Builder().build();
mCameraProvider = provider;
+ updateImageAndVideoRotationIfCameraIsReady();
+ updatePreviewRotationIfCameraIsReady();
startCameraAndTrackStates();
}
@@ -151,6 +185,19 @@
}
}, CameraXExecutors.mainThreadExecutor());
+
+ // Listen to display rotation and set target rotation for Preview.
+ mDisplayChangeListener = new DisplayChangeListener();
+
+ // Listen to accelerometer reading and set target rotation for ImageCapture and
+ // VideoCapture.
+ mAccelerometerRotationListener = new AccelerometerRotationListener(mAppContext) {
+ @Override
+ public void onRotationChanged(int rotation) {
+ mAccelerometerRotation = rotation;
+ updateImageAndVideoRotationIfCameraIsReady();
+ }
+ };
}
/**
@@ -165,21 +212,32 @@
/**
* Internal API used by {@link PreviewView} to notify changes.
- *
- * TODO(b/148791439): replace width/height with a Viewport.
*/
- @SuppressLint("MissingPermission")
+ @SuppressLint({"MissingPermission", "WrongConstant"})
@MainThread
- void attachPreviewSurface(@NonNull Preview.SurfaceProvider surfaceProvider, int width,
- int height) {
+ @UseExperimental(markerClass = ExperimentalUseCaseGroup.class)
+ void attachPreviewSurface(@NonNull Preview.SurfaceProvider surfaceProvider,
+ @NonNull ViewPort viewPort, @NonNull Display display) {
Threads.checkMainThread();
if (mSurfaceProvider != surfaceProvider) {
- mSurfaceProvider = surfaceProvider;
// Avoid setting provider unnecessarily which restarts Preview pipeline.
+ mSurfaceProvider = surfaceProvider;
if (mPreview != null) {
mPreview.setSurfaceProvider(surfaceProvider);
}
}
+ mViewPort = viewPort;
+ mPreviewDisplay = display;
+ // Update default rotation value with display rotation.
+ if (mAccelerometerRotation == INVALID_SURFACE_ROTATION) {
+ mAccelerometerRotation = display.getRotation();
+ updateImageAndVideoRotationIfCameraIsReady();
+ }
+ if (mDisplayRotation == INVALID_SURFACE_ROTATION) {
+ mDisplayRotation = display.getRotation();
+ updatePreviewRotationIfCameraIsReady();
+ }
+ startListeningToRotationEvents();
startCameraAndTrackStates();
}
@@ -198,6 +256,26 @@
}
mCamera = null;
mSurfaceProvider = null;
+ mViewPort = null;
+ mPreviewDisplay = null;
+ stopListeningToRotationEvents();
+ }
+
+ private void startListeningToRotationEvents() {
+ getDisplayManager().registerDisplayListener(mDisplayChangeListener,
+ new Handler(Looper.getMainLooper()));
+ if (mAccelerometerRotationListener.canDetectOrientation()) {
+ mAccelerometerRotationListener.enable();
+ }
+ }
+
+ private void stopListeningToRotationEvents() {
+ getDisplayManager().unregisterDisplayListener(mDisplayChangeListener);
+ mAccelerometerRotationListener.disable();
+ }
+
+ private DisplayManager getDisplayManager() {
+ return (DisplayManager) mAppContext.getSystemService(Context.DISPLAY_SERVICE);
}
// ----------------------
@@ -645,7 +723,6 @@
return mCamera.getCameraControl().enableTorch(torchEnabled);
}
- // TODO(b/148791439): Handle rotation so the output is always in gravity orientation.
// TODO(b/148791439): Give user a way to tell if the camera provider is ready.
/**
@@ -668,11 +745,11 @@
*/
@UseExperimental(markerClass = ExperimentalUseCaseGroup.class)
protected UseCaseGroup createUseCaseGroup() {
- if (mCameraProvider == null) {
+ if (mCameraProvider == null || mPreview == null) {
Logger.d(TAG, CAMERA_NOT_READY);
return null;
}
- if (mSurfaceProvider == null || mPreview == null) {
+ if (mSurfaceProvider == null || mViewPort == null) {
// Preview is required. Return early if preview Surface is not ready.
Logger.d(TAG, "Preview is not ready.");
return null;
@@ -687,7 +764,58 @@
builder.addUseCase(mVideoCapture);
}
- // TODO(b/148791439): set ViewPort if mPreviewSize/ LayoutDirection is not null.
+ builder.setViewPort(mViewPort);
return builder.build();
}
+
+ // Synthetic access
+ @SuppressWarnings("WeakerAccess")
+ @SuppressLint("WrongConstant")
+ void updateImageAndVideoRotationIfCameraIsReady() {
+ if (mAccelerometerRotation != INVALID_SURFACE_ROTATION && mImageCapture != null
+ && mVideoCapture != null) {
+ mImageCapture.setTargetRotation(mAccelerometerRotation);
+ mVideoCapture.setTargetRotation(mAccelerometerRotation);
+ }
+
+ }
+
+ @SuppressLint("WrongConstant")
+ @UseExperimental(markerClass = ExperimentalUseCaseGroup.class)
+ void updatePreviewRotationIfCameraIsReady() {
+ if (mDisplayRotation != INVALID_SURFACE_ROTATION && mPreview != null) {
+ mPreview.setTargetRotation(mDisplayRotation);
+ }
+ }
+
+ /**
+ * Listener for display changes.
+ *
+ * <p>When the device is rotated 180° from side to side, the activity is not
+ * destroyed and recreated, thus {@link #attachPreviewSurface} will not be invoked. This
+ * class is necessary to make sure preview's target rotation is the display rotation when
+ * that happens.
+ */
+ // Synthetic access
+ @SuppressWarnings("WeakerAccess")
+ class DisplayChangeListener implements DisplayManager.DisplayListener {
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ }
+
+ @SuppressLint("WrongConstant")
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (mPreviewDisplay != null && mPreview != null
+ && mPreviewDisplay.getDisplayId() == displayId) {
+ mDisplayRotation = mPreviewDisplay.getRotation();
+ updatePreviewRotationIfCameraIsReady();
+ }
+ }
+ }
}
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java b/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
index b66bed6..4b58b90 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
@@ -67,16 +67,17 @@
import java.util.concurrent.atomic.AtomicReference;
/**
- * Custom View that displays the camera feed for CameraX's Preview use case.
+ * Custom View that displays the camera feed for CameraX's {@link Preview} use case.
*
- * <p> This class manages the Surface lifecycle, as well as the preview aspect ratio and
- * orientation. Internally, it uses either a {@link TextureView} or {@link SurfaceView} to
- * display the camera feed.
+ * <p> This class manages the preview {@link Surface}'s lifecycle. It internally uses either a
+ * {@link TextureView} or {@link SurfaceView} to display the camera feed, and applies required
+ * transformations on them to correctly display the preview, this involves correcting their
+ * aspect ratio, scale and rotation.
*
* <p> If {@link PreviewView} uses a {@link SurfaceView} to display the preview
* stream, be careful when overlapping a {@link View} that's initially not visible (either
- * {@link View#INVISIBLE} or {@link View#GONE}) on top of it. When the
- * {@link SurfaceView} is attached to the display window, it calls
+ * {@link View#INVISIBLE} or {@link View#GONE}) on top of it. When the {@link SurfaceView} is
+ * attached to the display window, it calls
* {@link android.view.ViewParent#requestTransparentRegion(View)} which requests a computation of
* the transparent regions on the display. At this point, the {@link View} isn't visible, causing
* the overlapped region between the {@link SurfaceView} and the {@link View} to be
@@ -133,23 +134,17 @@
private float mDownX = 0F;
private float mDownY = 0F;
- private final OnLayoutChangeListener mOnLayoutChangeListener = new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
- int oldTop, int oldRight, int oldBottom) {
+ private final OnLayoutChangeListener mOnLayoutChangeListener =
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
- mPreviewViewMeteringPointFactory.setViewSize(getWidth(), getHeight());
- boolean isSizeChanged =
- right - left != oldRight - oldLeft || bottom - top != oldBottom - oldTop;
- if (isSizeChanged) {
- redrawPreview();
- }
- if (mCameraController != null && isSizeChanged) {
- mCameraController.attachPreviewSurface(getSurfaceProvider(), getWidth(),
- getHeight());
- }
- }
- };
+ mPreviewViewMeteringPointFactory.setViewSize(getWidth(), getHeight());
+ boolean isSizeChanged =
+ right - left != oldRight - oldLeft || bottom - top != oldBottom - oldTop;
+ if (isSizeChanged) {
+ redrawPreview();
+ attachToControllerIfReady();
+ }
+ };
private final Preview.SurfaceProvider mSurfaceProvider = new Preview.SurfaceProvider() {
@@ -248,10 +243,7 @@
mImplementation.onAttachedToWindow();
}
mPreviewViewMeteringPointFactory.setDisplay(getDisplay());
- if (mCameraController != null) {
- mCameraController.attachPreviewSurface(getSurfaceProvider(), getWidth(),
- getHeight());
- }
+ attachToControllerIfReady();
}
@Override
@@ -309,12 +301,13 @@
/**
* Sets the {@link ImplementationMode} for the {@link PreviewView}.
*
- * <p> {@link PreviewView} displays the preview with either a {@link SurfaceView} or a
- * {@link TextureView} depending on the mode. If not set, the default value is
- * {@link ImplementationMode#PERFORMANCE}.
- *
- * @see ImplementationMode
+ * <p> {@link PreviewView} displays the preview with a {@link TextureView} when the
+ * mode is {@link ImplementationMode#COMPATIBLE}, and tries to use a {@link SurfaceView} if
+ * it is {@link ImplementationMode#PERFORMANCE} when possible, which depends on the device's
+ * attributes (e.g. API level, camera hardware support level). If not set, the default mode
+ * is {@link ImplementationMode#PERFORMANCE}.
*/
+ @UiThread
public void setImplementationMode(@NonNull final ImplementationMode implementationMode) {
mImplementationMode = implementationMode;
}
@@ -327,24 +320,27 @@
*
* @return The {@link ImplementationMode} for {@link PreviewView}.
*/
+ @UiThread
@NonNull
public ImplementationMode getImplementationMode() {
return mImplementationMode;
}
/**
- * Gets the {@link Preview.SurfaceProvider} to be used with
- * {@link Preview#setSurfaceProvider(Executor, Preview.SurfaceProvider)}.
+ * Gets a {@link Preview.SurfaceProvider} to be used with
+ * {@link Preview#setSurfaceProvider(Executor, Preview.SurfaceProvider)}. This allows the
+ * camera feed to start when the {@link Preview} use case is bound to a lifecycle.
*
* <p> The returned {@link Preview.SurfaceProvider} will provide a preview {@link Surface} to
* the camera that's either managed by a {@link TextureView} or {@link SurfaceView} depending
- * on the {@link ImplementationMode}.
+ * on the {@link ImplementationMode} and the device's attributes (e.g. API level, camera
+ * hardware support level).
*
- * @return A {@link Preview.SurfaceProvider} used to start the camera preview.
+ * @return A {@link Preview.SurfaceProvider} to attach to a {@link Preview} use case.
* @see ImplementationMode
*/
- @NonNull
@UiThread
+ @NonNull
@UseExperimental(markerClass = ExperimentalUseCaseGroup.class)
public Preview.SurfaceProvider getSurfaceProvider() {
Threads.checkMainThread();
@@ -358,6 +354,7 @@
*
* @param scaleType A {@link ScaleType} to apply to the preview.
*/
+ @UiThread
public void setScaleType(@NonNull final ScaleType scaleType) {
mPreviewTransform.setScaleType(scaleType);
mPreviewViewMeteringPointFactory.setScaleType(scaleType);
@@ -371,49 +368,54 @@
*
* @return The {@link ScaleType} currently applied to the preview.
*/
+ @UiThread
@NonNull
public ScaleType getScaleType() {
return mPreviewTransform.getScaleType();
}
/**
- * Gets the {@link MeteringPointFactory} for the Camera currently connected to the PreviewView.
+ * Gets the {@link MeteringPointFactory} for the camera currently connected to the
+ * {@link PreviewView}, if any.
*
* <p>The returned {@link MeteringPointFactory} is capable of creating {@link MeteringPoint}s
* from (x, y) coordinates in the {@link PreviewView}. This conversion takes into account its
* {@link ScaleType}.
*
* <p>When the PreviewView has a width and/or height equal to zero, or when a preview
- * {@link Surface} is not yet requested, the returned factory will always create invalid
- * {@link MeteringPoint}s which could lead to the failure of
- * {@link androidx.camera.core.CameraControl#startFocusAndMetering(FocusMeteringAction)} but it
- * won't cause any crash.
+ * {@link Surface} is not yet requested by the camera, the returned factory will always create
+ * invalid {@link MeteringPoint}s which could lead to the failure of
+ * {@link androidx.camera.core.CameraControl#startFocusAndMetering(FocusMeteringAction)}, but it
+ * won't cause the application to crash.
*
* @return a {@link MeteringPointFactory}
*/
+ @UiThread
@NonNull
public MeteringPointFactory getMeteringPointFactory() {
return mPreviewViewMeteringPointFactory;
}
/**
- * Gets the {@link LiveData} of current preview {@link StreamState}.
+ * Gets a {@link LiveData} for the preview {@link StreamState}.
*
- * <p>There are two states, {@link StreamState#IDLE} and {@link StreamState#STREAMING}.
- * {@link StreamState#IDLE} represents the preview is currently not visible and streaming is
- * stopped. {@link StreamState#STREAMING} means the preview is streaming.
+ * <p>There are two preview stream states, {@link StreamState#IDLE} and
+ * {@link StreamState#STREAMING}. {@link StreamState#IDLE} indicates the preview is currently
+ * not visible and streaming is stopped. {@link StreamState#STREAMING} means the preview is
+ * streaming or is about to start streaming. This state guarantees the preview is visible
+ * only when the {@link ImplementationMode} is {@link ImplementationMode#COMPATIBLE}. When in
+ * {@link ImplementationMode#PERFORMANCE} mode, it is possible the preview becomes
+ * visible slightly after the state changes to {@link StreamState#STREAMING}.
*
- * <p>When {@link PreviewView} is in a {@link StreamState#STREAMING} state, it guarantees
- * preview is visible only when implementationMode is {@link ImplementationMode#COMPATIBLE}.
- * When in {@link ImplementationMode#PERFORMANCE} mode, it is possible that preview becomes
- * visible slightly after state changes to {@link StreamState#STREAMING}. For apps
- * relying on the preview visible signal to be working correctly, please set
- * {@link ImplementationMode#COMPATIBLE} mode in
- * {@link #setImplementationMode}.
+ * <p>Apps that require a precise signal for when the preview starts should
+ * {@linkplain #setImplementationMode(ImplementationMode) set} the implementation mode to
+ * {@link ImplementationMode#COMPATIBLE}.
*
- * @return A {@link LiveData} containing the {@link StreamState}. Apps can either get current
- * value by {@link LiveData#getValue()} or register a observer by {@link LiveData#observe} .
+ * @return A {@link LiveData} of the preview's {@link StreamState}. Apps can get the current
+ * state with {@link LiveData#getValue()}, or register an observer with
+ * {@link LiveData#observe} .
*/
+ @UiThread
@NonNull
public LiveData<StreamState> getPreviewStreamState() {
return mPreviewStreamStateLiveData;
@@ -439,6 +441,7 @@
* @return A {@link Bitmap.Config#ARGB_8888} {@link Bitmap} representing the content
* displayed on the preview {@link Surface}, or null if the camera preview hasn't started yet.
*/
+ @UiThread
@Nullable
public Bitmap getBitmap() {
return mImplementation == null ? null : mImplementation.getBitmap();
@@ -455,6 +458,7 @@
* @see ViewPort
* @see UseCaseGroup
*/
+ @UiThread
@Nullable
@ExperimentalUseCaseGroup
public ViewPort getViewPort() {
@@ -490,7 +494,7 @@
* ViewPort viewPort = previewView.getViewPort(targetRotation);
* UseCaseGroup useCaseGroup =
* new UseCaseGroup.Builder().setViewPort(viewPort).addUseCase(preview).build();
- * cameraProvider.bindToLifecycle(this, cameraSelector, useCaseGroup);
+ * cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup);
* </code></pre>
*
* <p> Note that for non-display rotation to work, the mode must be set to
@@ -502,6 +506,7 @@
* {@link Surface#ROTATION_270}.
* @see ImplementationMode
*/
+ @UiThread
@SuppressLint("WrongConstant")
@Nullable
@ExperimentalUseCaseGroup
@@ -587,17 +592,18 @@
* {@link TextureView} instead.
*
* <p>{@link PreviewView} falls back to {@link TextureView} when the API level is 24 or
- * lower, the camera hardware is
+ * lower, the camera hardware support level is
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}, or
* {@link Preview#getTargetRotation()} is different from {@link PreviewView}'s display
* rotation.
*
* <p>Do not use this mode if {@link Preview.Builder#setTargetRotation(int)} is set
* to a value different than the display's rotation, because {@link SurfaceView} does not
- * support arbitrary transformation. Do not use this mode if the {@link PreviewView}
+ * support arbitrary rotations. Do not use this mode if the {@link PreviewView}
* needs to be animated. {@link SurfaceView} animation is not supported on API level 24
- * or lower. Also, for streaming state provided in {@link #getPreviewStreamState}, the
- * {@link StreamState#STREAMING} state might happen prematurely if this mode is used.
+ * or lower. Also, for the preview's streaming state provided in
+ * {@link #getPreviewStreamState}, the {@link StreamState#STREAMING} state might happen
+ * prematurely if this mode is used.
*
* @see Preview.Builder#setTargetRotation(int)
* @see Preview.Builder#getTargetRotation()
@@ -693,7 +699,7 @@
}
/**
- * Definitions for current preview stream state.
+ * Definitions for the preview stream state.
*/
public enum StreamState {
/** Preview is not visible yet. */
@@ -701,10 +707,10 @@
/**
* Preview is streaming.
*
- * It only guarantees preview streaming when implementation mode is
- * {@link ImplementationMode#COMPATIBLE}. When in {@link ImplementationMode#PERFORMANCE},
- * it is possible that preview becomes visible slightly after state is changed. For apps
- * relying on the preview visible signal to work correctly, please set
+ * <p>This state only guarantees the preview is streaming when the implementation mode is
+ * {@link ImplementationMode#COMPATIBLE}. When in {@link ImplementationMode#PERFORMANCE}
+ * mode, it is possible that the preview becomes visible slightly after the state has
+ * changed. For apps requiring a precise signal for when the preview starts, please set
* {@link ImplementationMode#PERFORMANCE} mode via {@link #setImplementationMode}.
*/
STREAMING
@@ -743,10 +749,7 @@
mCameraController.clearPreviewSurface();
}
mCameraController = cameraController;
- if (mCameraController != null) {
- mCameraController.attachPreviewSurface(getSurfaceProvider(), getWidth(),
- getHeight());
- }
+ attachToControllerIfReady();
}
/**
@@ -761,4 +764,14 @@
Threads.checkMainThread();
return mCameraController;
}
+
+ @UseExperimental(markerClass = ExperimentalUseCaseGroup.class)
+ private void attachToControllerIfReady() {
+ Display display = getDisplay();
+ ViewPort viewPort = getViewPort();
+ if (mCameraController != null && viewPort != null && isAttachedToWindow()
+ && display != null) {
+ mCameraController.attachPreviewSurface(getSurfaceProvider(), viewPort, display);
+ }
+ }
}
diff --git a/camera/integration-tests/camerapipetestapp/build.gradle b/camera/integration-tests/camerapipetestapp/build.gradle
index 13156be..af70051 100644
--- a/camera/integration-tests/camerapipetestapp/build.gradle
+++ b/camera/integration-tests/camerapipetestapp/build.gradle
@@ -56,6 +56,7 @@
// Android Support Library
implementation("androidx.appcompat:appcompat:1.1.0")
+ implementation(CONSTRAINT_LAYOUT, { transitive = true })
// Camera Pipe
implementation(project(":camera:camera-camera2-pipe"))
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt
index e87a73d..4e29e3e 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt
@@ -17,120 +17,58 @@
package androidx.camera.integration.camera2.pipe
import android.app.Activity
+import android.hardware.camera2.CameraCharacteristics
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.View
-import android.view.ViewGroup
import android.view.WindowManager
-import android.widget.RelativeLayout
+import androidx.camera.camera2.pipe.CameraId
import androidx.camera.camera2.pipe.CameraPipe
-import androidx.camera.camera2.pipe.CameraTimestamp
-import androidx.camera.camera2.pipe.FrameInfo
-import androidx.camera.camera2.pipe.FrameNumber
-import androidx.camera.camera2.pipe.Request
-import androidx.camera.camera2.pipe.RequestMetadata
-import androidx.camera.integration.camera2.pipe.dataholders.GraphDataHolder
-import androidx.camera.integration.camera2.pipe.dataholders.GraphDataHolderStateImpl
-import androidx.camera.integration.camera2.pipe.dataholders.GraphDataHolderValueImpl
-import androidx.camera.integration.camera2.pipe.dataholders.KeyValueDataHolder
-import androidx.camera.integration.camera2.pipe.transformations.DataTransformations1D
-import androidx.camera.integration.camera2.pipe.transformations.DataTransformationsKeyValue
-import androidx.camera.integration.camera2.pipe.visualizations.KeyValueView
-import androidx.camera.integration.camera2.pipe.visualizations.Paints
-import androidx.camera.integration.camera2.pipe.visualizations.StateGraphView
-import androidx.camera.integration.camera2.pipe.visualizations.ValueGraphView
-import kotlinx.android.synthetic.main.activity_main.graphs
-import kotlinx.android.synthetic.main.activity_main.key_values
-import kotlinx.android.synthetic.main.graph_layout.view.graph_layout
-import kotlinx.android.synthetic.main.graph_layout.view.graph_view_layout
-import kotlinx.android.synthetic.main.graph_layout.view.top_row_layout
-import kotlinx.android.synthetic.main.key_value_layout.view.key_name
-import kotlinx.android.synthetic.main.key_value_layout.view.key_value_layout
-import kotlinx.android.synthetic.main.key_value_layout.view.value_layout
+/**
+ * This is the main activity for the CameraPipe test application.
+ */
class CameraPipeActivity : Activity() {
- private lateinit var dataManager: DataManager
- private lateinit var dataListener: DataListener
- private lateinit var dataGenerator: DataGenerator
- private lateinit var paints: Paints
- private lateinit var viewfinder: Viewfinder
-
private lateinit var cameraPipe: CameraPipe
+ private lateinit var dataVisualizations: DataVisualizations
+ private lateinit var ui: CameraPipeUi
+
+ private var lastCameraId: CameraId? = null
private var currentCamera: SimpleCamera? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.i("CXCP-App", "Activity onCreate")
+ // This adjusts the UI to make the activity run a a full screen application.
configureFullScreenCameraWindow()
cameraPipe = (applicationContext as CameraPipeApplication).cameraPipe
- setContentView(R.layout.activity_main)
- viewfinder = findViewById(R.id.viewfinder)
- paints = Paints(this)
+ // Inflate the main ui for the camera activity.
+ ui = CameraPipeUi.inflate(this)
- val beginTimeNanos = System.nanoTime()
+ // Configure and wire up basic UI behaviors.
+ ui.disableButton(ui.captureButton)
+ ui.disableButton(ui.infoButton)
+ ui.viewfinderText.visibility = View.VISIBLE
+ ui.switchButton.setOnClickListener { startNextCamera() }
- // Initialize manager of data holders for visualizations, and data holders themselves
- dataManager = DataManager(VisualizationDefaults)
- dataManager.initializeDataHolders()
-
- // Initialize the listener of new data
- dataListener = DataListener(
- dataManager,
- DataTransformationsKeyValue,
- DataTransformations1D,
- beginTimeNanos
- )
-
- // Initialize the data generator and start generating data, noting the begin timestamp
- dataGenerator = DataGenerator(
- dataListener,
- VisualizationDefaults
- )
- dataGenerator.beginTimeNanos = beginTimeNanos
-
- // Set up the views powered by data holders, and plug in the data holders
- setUpVisualizations()
+ // TODO: Update this to work with newer versions of the visualizations and to accept
+ // the CameraPipeUi object as a parameter.
+ dataVisualizations = DataVisualizations(this)
}
override fun onStart() {
super.onStart()
Log.i("CXCP-App", "Activity onStart")
- if (currentCamera == null) {
- dataGenerator.runDataGenerators()
- currentCamera = SimpleCamera.create(cameraPipe, viewfinder, listOf(object : Request
- .Listener {
- override fun onStarted(
- requestMetadata: RequestMetadata,
- frameNumber: FrameNumber,
- timestamp: CameraTimestamp
- ) {
-// Log.i("PJR", "OnStart: $frameNumber")
- // TODO: Implement the onStarted event to get frameNumber(s) and timestamps
- }
-
- override fun onTotalCaptureResult(
- requestMetadata: RequestMetadata,
- frameNumber: FrameNumber,
- totalCaptureResult: FrameInfo
- ) {
-// Log.i("PJR", "onTotalCaptureResult: $frameNumber")
- }
-
- override fun onComplete(
- requestMetadata: RequestMetadata,
- frameNumber: FrameNumber,
- result: FrameInfo
- ) {
- Log.i("PJR", "onComplete: $frameNumber")
- // TODO: Implement the onComplete event to write out Metadata
- }
- }))
+ val camera = currentCamera
+ if (camera == null) {
+ startNextCamera()
+ } else {
+ camera.start()
}
- currentCamera!!.start()
}
override fun onResume() {
@@ -147,16 +85,49 @@
super.onStop()
Log.i("CXCP-App", "Activity onStop")
currentCamera?.stop()
-
- // TODO: Stop data generation threads here, but do not stall the app waiting for the threads
- // to quit.
}
override fun onDestroy() {
super.onDestroy()
Log.i("CXCP-App", "Activity onDestroy")
currentCamera?.close()
- dataGenerator.quitDataGenerators()
+ dataVisualizations.close()
+ }
+
+ private fun startNextCamera() {
+ var camera = currentCamera
+ camera?.stop()
+
+ val cameraId = findNextCamera(lastCameraId)
+ camera = SimpleCamera.create(cameraPipe, cameraId, ui.viewfinder, listOf())
+ currentCamera = camera
+ lastCameraId = cameraId
+ ui.viewfinderText.text = camera.cameraInfoString()
+
+ camera.start()
+ }
+
+ private fun findNextCamera(lastCameraId: CameraId?): CameraId {
+ // By default, open the first back facing camera if no camera was previously configured.
+ if (lastCameraId == null) {
+ return cameraPipe.cameras().findAll().firstOrNull {
+ cameraPipe.cameras().awaitMetadata(it)[CameraCharacteristics.LENS_FACING] ==
+ CameraCharacteristics.LENS_FACING_BACK
+ } ?: cameraPipe.cameras().findAll().first()
+ }
+
+ // If a camera was previously open, select the next camera in the list of all cameras. It is
+ // possible that the list of cameras contains only one camera, in which case this will return
+ // the same camera as "currentCameraId"
+ val cameras: List<CameraId> = cameraPipe.cameras().findAll()
+ val lastCameraIndex = cameras.indexOf(lastCameraId)
+ if (cameras.isEmpty() || lastCameraIndex == -1) {
+ Log.e("CXCP-App", "Failed to find matching camera!")
+ return cameraPipe.cameras().findAll().first()
+ }
+
+ // When we reach the end of the list of cameras, loop.
+ return cameras[(lastCameraIndex + 1) % cameras.size]
}
@Suppress("DEPRECATION")
@@ -191,105 +162,4 @@
}
window.attributes = windowParams
}
-
- /** Sets up all the different types of visualizations */
- private fun setUpVisualizations() {
- setUpKeyValueVisualizations(dataManager.keyValueDataHolders, dataManager.graphDataHolders)
- setUpGraphVisualizations(dataManager.keyValueDataHolders, dataManager.graphDataHolders)
- }
-
- private fun setUpKeyValueVisualizations(
- keyValeDataHolders: Map<CameraMetadataKey, KeyValueDataHolder>,
- graphDataHolders: Map<CameraMetadataKey, GraphDataHolder>
- ) {
- val heightPixels = 30
-
- keyValeDataHolders.forEach loop@{
- if (graphDataHolders.containsKey(it.key)) return@loop
- val dataHolder = it.value
- val keyValueView =
- KeyValueView(
- this,
- dataHolder,
- paints
- )
-
- val keyValueLayout = View.inflate(this, R.layout.key_value_layout, null)
- keyValueLayout.key_name.text = "${it.key.name} "
-
- val keyValueViewParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams
- .MATCH_PARENT, heightPixels)
- keyValueView.layoutParams = keyValueViewParams
-
- keyValueLayout.key_value_layout.value_layout.addView(keyValueView)
- key_values.addView(keyValueLayout)
- }
- }
-
- /** Sets up the graph visualizations specifically */
- private fun setUpGraphVisualizations(
- keyValeDataHolders: Map<CameraMetadataKey, KeyValueDataHolder>,
- graphDataHolders: Map<CameraMetadataKey, GraphDataHolder>
- ) {
- val heightPixels = 110
-
- graphDataHolders.forEach {
- val key = it.key
- val dataHolder = it.value
- val graphView = when (dataHolder) {
- is GraphDataHolderValueImpl -> ValueGraphView(
- this,
- dataGenerator.beginTimeNanos,
- dataHolder,
- paints
- )
- is GraphDataHolderStateImpl -> StateGraphView(
- this,
- dataGenerator.beginTimeNanos,
- dataHolder,
- paints = paints
- )
- else -> throw Exception("Visualization is not supported for this graphDataHolder " +
- "implementation")
- }
-
- val graphLayout = View.inflate(this, R.layout.graph_layout, null)
-
- val graphViewParams = RelativeLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- heightPixels
- )
- graphViewParams.addRule(RelativeLayout.BELOW, graphLayout.top_row_layout.id)
- graphView.layoutParams = graphViewParams
-
- graphLayout.graph_view_layout.addView(graphView)
- graphLayout.graph_layout.setBackgroundResource(R.drawable.graph_background)
-
- val graphLayoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams
- .WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
- graphLayoutParams.setMargins(0, 0, 0, 20)
- graphLayout.layoutParams = graphLayoutParams
-
- val keyValueDataHolder = keyValeDataHolders[key]
- if (keyValueDataHolder != null) {
- val keyValueView =
- KeyValueView(
- this,
- keyValueDataHolder,
- paints
- )
- val keyValueLayout = View.inflate(this, R.layout.key_value_layout, null)
- keyValueLayout.key_name.text = "${it.key.name} "
-
- val keyValueViewParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams
- .MATCH_PARENT, 30)
- keyValueView.layoutParams = keyValueViewParams
-
- keyValueLayout.key_value_layout.value_layout.addView(keyValueView)
- graphLayout.top_row_layout.addView(keyValueLayout)
- }
-
- graphs.addView(graphLayout)
- }
- }
}
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeUi.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeUi.kt
new file mode 100644
index 0000000..feb1ac4
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeUi.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2020 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 androidx.camera.integration.camera2.pipe
+
+import android.app.Activity
+import android.graphics.drawable.Drawable
+import android.view.View
+import android.widget.ImageButton
+import android.widget.LinearLayout
+import android.widget.ScrollView
+import android.widget.TextView
+
+class CameraPipeUi private constructor(activity: Activity) {
+ companion object {
+ /**
+ * Set the content view for the activity and then bind basic interactions together.
+ */
+ fun inflate(activity: Activity): CameraPipeUi {
+ activity.setContentView(R.layout.activity_main)
+ return CameraPipeUi(activity)
+ }
+ }
+
+ val viewfinder: Viewfinder = activity.findViewById(R.id.viewfinder)
+ val viewfinderText: TextView = activity.findViewById(R.id.viewfinder_text)
+ val switchButton: ImageButton = activity.findViewById(R.id.switch_button)
+ val captureButton: ImageButton = activity.findViewById(R.id.capture_button)
+ val infoButton: ImageButton = activity.findViewById(R.id.info_button)
+ val infoView: LinearLayout = activity.findViewById(R.id.info_content)
+ val infoText: TextView = activity.findViewById(R.id.info_text)
+
+ @Suppress("DEPRECATION")
+ private val recordBackground: Drawable = activity.resources.getDrawable(
+ R.drawable.theme_round_button_record
+ )
+
+ @Suppress("DEPRECATION")
+ private val defaultBackground: Drawable = activity.resources.getDrawable(
+ R.drawable.theme_round_button_default
+ )
+
+ init {
+ val infoViewContainer: ScrollView = activity.findViewById(R.id.info_view)
+ infoButton.setOnClickListener {
+ if (infoViewContainer.visibility == View.VISIBLE) {
+ infoViewContainer.visibility = View.INVISIBLE
+ } else {
+ infoViewContainer.visibility = View.VISIBLE
+ infoViewContainer.isClickable = true
+ }
+ }
+ infoView.setOnClickListener { infoViewContainer.visibility = View.INVISIBLE }
+ }
+
+ fun disableButton(button: ImageButton) {
+ button.background = defaultBackground
+ button.isEnabled = false
+ button.alpha = 0.25f
+ }
+
+ fun enableButton(button: ImageButton) {
+ button.background = defaultBackground
+ button.isEnabled = true
+ button.alpha = 1.0f
+ }
+
+ fun enableRecordingButton(button: ImageButton) {
+ button.background = recordBackground
+ button.isEnabled = true
+ button.alpha = 1.0f
+ }
+}
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/DataVisualizations.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/DataVisualizations.kt
new file mode 100644
index 0000000..2278003
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/DataVisualizations.kt
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2020 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 androidx.camera.integration.camera2.pipe
+
+import android.app.Activity
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import android.widget.RelativeLayout
+import androidx.camera.integration.camera2.pipe.dataholders.GraphDataHolder
+import androidx.camera.integration.camera2.pipe.dataholders.GraphDataHolderStateImpl
+import androidx.camera.integration.camera2.pipe.dataholders.GraphDataHolderValueImpl
+import androidx.camera.integration.camera2.pipe.dataholders.KeyValueDataHolder
+import androidx.camera.integration.camera2.pipe.transformations.DataTransformations1D
+import androidx.camera.integration.camera2.pipe.transformations.DataTransformationsKeyValue
+import androidx.camera.integration.camera2.pipe.visualizations.KeyValueView
+import androidx.camera.integration.camera2.pipe.visualizations.Paints
+import androidx.camera.integration.camera2.pipe.visualizations.StateGraphView
+import androidx.camera.integration.camera2.pipe.visualizations.ValueGraphView
+import kotlinx.android.synthetic.main.graph_layout.view.graph_layout
+import kotlinx.android.synthetic.main.graph_layout.view.graph_view_layout
+import kotlinx.android.synthetic.main.graph_layout.view.top_row_layout
+import kotlinx.android.synthetic.main.key_value_layout.view.key_name
+import kotlinx.android.synthetic.main.key_value_layout.view.key_value_layout
+import kotlinx.android.synthetic.main.key_value_layout.view.value_layout
+
+class DataVisualizations(activity: Activity) {
+ private var dataManager: DataManager
+ private var dataListener: DataListener
+ private var dataGenerator: DataGenerator
+ private var paints: Paints
+
+ private val context: Context
+
+ init {
+ context = activity
+ paints = Paints(activity)
+
+ val beginTimeNanos = System.nanoTime()
+
+ // Initialize manager of data holders for visualizations, and data holders themselves
+ dataManager = DataManager(VisualizationDefaults)
+ dataManager.initializeDataHolders()
+
+ // Initialize the listener of new data
+ dataListener = DataListener(
+ dataManager,
+ DataTransformationsKeyValue,
+ DataTransformations1D,
+ beginTimeNanos
+ )
+
+ // Initialize the data generator and start generating data, noting the begin timestamp
+ dataGenerator = DataGenerator(
+ dataListener,
+ VisualizationDefaults
+ )
+ dataGenerator.beginTimeNanos = beginTimeNanos
+
+ // Set up the views powered by data holders, and plug in the data holders
+ setUpVisualizations()
+ }
+
+ fun start() {
+ // TODO(codelogic): Attach and start the data visualizer.
+// dataGenerator.runDataGenerators()
+ }
+
+ fun stop() {
+ // TODO(codelogic): Unregister and clear visualizations
+ }
+
+ fun close() {
+ }
+
+ /** Sets up all the different types of visualizations */
+ private fun setUpVisualizations() {
+ setUpKeyValueVisualizations(dataManager.keyValueDataHolders, dataManager.graphDataHolders)
+ setUpGraphVisualizations(dataManager.keyValueDataHolders, dataManager.graphDataHolders)
+ }
+
+ private fun setUpKeyValueVisualizations(
+ keyValeDataHolders: Map<CameraMetadataKey, KeyValueDataHolder>,
+ graphDataHolders: Map<CameraMetadataKey, GraphDataHolder>
+ ) {
+ val heightPixels = 30
+
+ keyValeDataHolders.forEach loop@{
+ if (graphDataHolders.containsKey(it.key)) return@loop
+ val dataHolder = it.value
+ val keyValueView =
+ KeyValueView(
+ context,
+ dataHolder,
+ paints
+ )
+
+ val keyValueLayout = View.inflate(context, R.layout.key_value_layout, null)
+ keyValueLayout.key_name.text = "${it.key.name} "
+
+ val keyValueViewParams = RelativeLayout.LayoutParams(
+ ViewGroup.LayoutParams
+ .MATCH_PARENT, heightPixels)
+ keyValueView.layoutParams = keyValueViewParams
+
+ keyValueLayout.key_value_layout.value_layout.addView(keyValueView)
+// kotlinx.android.synthetic.main.activity_main. .addView(keyValueLayout)
+ }
+ }
+
+ /** Sets up the graph visualizations specifically */
+ private fun setUpGraphVisualizations(
+ keyValeDataHolders: Map<CameraMetadataKey, KeyValueDataHolder>,
+ graphDataHolders: Map<CameraMetadataKey, GraphDataHolder>
+ ) {
+ val heightPixels = 110
+
+ graphDataHolders.forEach {
+ val key = it.key
+ val dataHolder = it.value
+ val graphView = when (dataHolder) {
+ is GraphDataHolderValueImpl -> ValueGraphView(
+ context,
+ dataGenerator.beginTimeNanos,
+ dataHolder,
+ paints
+ )
+ is GraphDataHolderStateImpl -> StateGraphView(
+ context,
+ dataGenerator.beginTimeNanos,
+ dataHolder,
+ paints = paints
+ )
+ else -> throw Exception("Visualization is not supported for this graphDataHolder " +
+ "implementation")
+ }
+
+ val graphLayout = View.inflate(context, R.layout.graph_layout, null)
+
+ val graphViewParams = RelativeLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ heightPixels
+ )
+ graphViewParams.addRule(RelativeLayout.BELOW, graphLayout.top_row_layout.id)
+ graphView.layoutParams = graphViewParams
+
+ graphLayout.graph_view_layout.addView(graphView)
+ graphLayout.graph_layout.setBackgroundResource(R.drawable.graph_background)
+
+ val graphLayoutParams = RelativeLayout.LayoutParams(
+ ViewGroup.LayoutParams
+ .WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ graphLayoutParams.setMargins(0, 0, 0, 20)
+ graphLayout.layoutParams = graphLayoutParams
+
+ val keyValueDataHolder = keyValeDataHolders[key]
+ if (keyValueDataHolder != null) {
+ val keyValueView =
+ KeyValueView(
+ context,
+ keyValueDataHolder,
+ paints
+ )
+ val keyValueLayout = View.inflate(context, R.layout.key_value_layout, null)
+ keyValueLayout.key_name.text = "${it.key.name} "
+
+ val keyValueViewParams = RelativeLayout.LayoutParams(
+ ViewGroup.LayoutParams
+ .MATCH_PARENT, 30)
+ keyValueView.layoutParams = keyValueViewParams
+
+ keyValueLayout.key_value_layout.value_layout.addView(keyValueView)
+ graphLayout.top_row_layout.addView(keyValueLayout)
+ }
+
+// graphs.addView(graphLayout)
+ }
+ }
+}
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/SimpleCamera.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/SimpleCamera.kt
index f404acb..d86f84e 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/SimpleCamera.kt
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/SimpleCamera.kt
@@ -19,12 +19,15 @@
import android.graphics.ImageFormat
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
import android.media.ImageReader
import android.os.Handler
import android.util.Log
import android.util.Size
import android.view.Surface
import androidx.camera.camera2.pipe.CameraGraph
+import androidx.camera.camera2.pipe.CameraId
+import androidx.camera.camera2.pipe.CameraMetadata
import androidx.camera.camera2.pipe.CameraPipe
import androidx.camera.camera2.pipe.Request
import androidx.camera.camera2.pipe.RequestTemplate
@@ -33,33 +36,30 @@
import androidx.camera.camera2.pipe.StreamType
import kotlin.math.absoluteValue
+private const val defaultWidth = 1280
+private const val defaultHeight = 720
+private const val defaultAspectRatio = defaultWidth.toDouble() / defaultHeight.toDouble()
+
class SimpleCamera(
+ private val cameraId: CameraId,
+ private val cameraMetadata: CameraMetadata,
private val cameraGraph: CameraGraph,
private val imageReader: ImageReader
) {
companion object {
- private val defaultResolution = Size(1280, 720)
- private const val defaultAspectRatio = 4.0 / 3.0
-
fun create(
cameraPipe: CameraPipe,
+ cameraId: CameraId,
viewfinder: Viewfinder,
listeners: List<Request.Listener> = emptyList()
): SimpleCamera {
// TODO: It may be worthwhile to turn this into a suspending function to avoid running
// camera-finding and metadata querying on the main thread.
- // Find first back facing camera, or any camera id at all if the back facing camera is
- // not available.
- val cameraId = cameraPipe.cameras().findAll().firstOrNull() {
- cameraPipe.cameras().awaitMetadata(it)[CameraCharacteristics.LENS_FACING] ==
- CameraCharacteristics.LENS_FACING_BACK
- } ?: cameraPipe.cameras().findAll().first()
-
Log.i("CXCP-App", "Selected $cameraId to open.")
- val metadata = cameraPipe.cameras().awaitMetadata(cameraId)
- val yuvSizes = metadata.streamMap.getOutputSizes(ImageFormat.YUV_420_888)
+ val cameraMetadata = cameraPipe.cameras().awaitMetadata(cameraId)
+ val yuvSizes = cameraMetadata.streamMap.getOutputSizes(ImageFormat.YUV_420_888)
val yuv43Sizes = yuvSizes.filter {
(((it.width.toDouble() / it.height.toDouble()) - defaultAspectRatio).absoluteValue
< 0.001)
@@ -67,8 +67,8 @@
// Find the size that is the least different
val yuvSize = yuv43Sizes.minByOrNull {
- ((it.width * it.height) - (defaultResolution.width *
- defaultResolution.height)).absoluteValue
+ ((it.width * it.height) - (defaultWidth *
+ defaultHeight)).absoluteValue
}!!
Log.i("CXCP-App", "Selected $yuvSize as the YUV output size")
@@ -122,7 +122,7 @@
10
)
cameraGraph.setSurface(yuvStream.id, imageReader.surface)
- return SimpleCamera(cameraGraph, imageReader)
+ return SimpleCamera(cameraId, cameraMetadata, cameraGraph, imageReader)
}
}
@@ -153,4 +153,37 @@
cameraGraph.close()
imageReader.close()
}
+
+ fun cameraInfoString(): String {
+ val lensFacing = when (cameraMetadata[CameraCharacteristics.LENS_FACING]) {
+ CameraCharacteristics.LENS_FACING_FRONT -> "Front"
+ CameraCharacteristics.LENS_FACING_BACK -> "Back"
+ CameraCharacteristics.LENS_FACING_EXTERNAL -> "External"
+ else -> "Unknown"
+ }
+
+ val capabilities = cameraMetadata[CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES]
+ val cameraType = if (capabilities != null &&
+ capabilities.contains(REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)
+ ) {
+ "Logical"
+ } else {
+ "Physical"
+ }
+
+ return StringBuilder().apply {
+ append("$cameraGraph (Camera ${cameraId.value})\n")
+ append(" Facing: $lensFacing ($cameraType)\n")
+ append("Streams:")
+ for (stream in cameraGraph.streams) {
+ append("\n ")
+ append(stream.value.id.toString().padEnd(12, ' '))
+ append(stream.value.size.toString().padEnd(12, ' '))
+ append(stream.value.format.name.padEnd(16, ' '))
+ append(stream.value.type.toString().padEnd(16, ' '))
+ }
+
+ // TODO: Add static configuration info.
+ }.toString()
+ }
}
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable-v24/ic_launcher_foreground.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable-v24/ic_launcher_foreground.xml
deleted file mode 100644
index c162111..0000000
--- a/camera/integration-tests/camerapipetestapp/src/main/res/drawable-v24/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<!-- Copyright (C) 2020 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:aapt="http://schemas.android.com/aapt"
- android:width="108dp"
- android:height="108dp"
- android:viewportHeight="108"
- android:viewportWidth="108">
- <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
- <aapt:attr name="android:fillColor">
- <gradient
- android:endX="85.84757"
- android:endY="92.4963"
- android:startX="42.9492"
- android:startY="49.59793"
- android:type="linear">
- <item
- android:color="#44000000"
- android:offset="0.0" />
- <item
- android:color="#00000000"
- android:offset="1.0" />
- </gradient>
- </aapt:attr>
- </path>
- <path
- android:fillColor="#FFFFFF"
- android:fillType="nonZero"
- android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
- android:strokeColor="#00000000"
- android:strokeWidth="1" />
-</vector>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_baseline_flip_camera_android_24.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_baseline_flip_camera_android_24.xml
new file mode 100644
index 0000000..85e5bca
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_baseline_flip_camera_android_24.xml
@@ -0,0 +1,23 @@
+<!--
+ Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector android:height="24dp" android:tint="#FFFFFF"
+ android:viewportHeight="24" android:viewportWidth="24"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="@android:color/white" android:pathData="M9,12c0,1.66 1.34,3 3,3s3,-1.34 3,-3s-1.34,-3 -3,-3S9,10.34 9,12z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M8,10V8H5.09C6.47,5.61 9.05,4 12,4c3.72,0 6.85,2.56 7.74,6h2.06c-0.93,-4.56 -4.96,-8 -9.8,-8C8.73,2 5.82,3.58 4,6.01V4H2v6H8z"/>
+ <path android:fillColor="@android:color/white" android:pathData="M16,14v2h2.91c-1.38,2.39 -3.96,4 -6.91,4c-3.72,0 -6.85,-2.56 -7.74,-6H2.2c0.93,4.56 4.96,8 9.8,8c3.27,0 6.18,-1.58 8,-4.01V20h2v-6H16z"/>
+</vector>
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_baseline_photo_camera_24.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_baseline_photo_camera_24.xml
new file mode 100644
index 0000000..c6f0df49
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_baseline_photo_camera_24.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector android:height="24dp" android:tint="#FFFFFF"
+ android:viewportHeight="24" android:viewportWidth="24"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="@android:color/white" android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
+ <path android:fillColor="@android:color/white" android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
+</vector>
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_background.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_background.xml
index 47d3f33..ca3826a 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_background.xml
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_background.xml
@@ -1,184 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="108dp"
+<vector
android:height="108dp"
+ android:width="108dp"
android:viewportHeight="108"
- android:viewportWidth="108">
- <path
- android:fillColor="#3DDC84"
- android:pathData="M0,0h108v108h-108z" />
- <path
- android:fillColor="#00000000"
- android:pathData="M9,0L9,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,0L19,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M29,0L29,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M39,0L39,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M49,0L49,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M59,0L59,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M69,0L69,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M79,0L79,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M89,0L89,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M99,0L99,108"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,9L108,9"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,19L108,19"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,29L108,29"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,39L108,39"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,49L108,49"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,59L108,59"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,69L108,69"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,79L108,79"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,89L108,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M0,99L108,99"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,29L89,29"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,39L89,39"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,49L89,49"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,59L89,59"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,69L89,69"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M19,79L89,79"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M29,19L29,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M39,19L39,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M49,19L49,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M59,19L59,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M69,19L69,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
- <path
- android:fillColor="#00000000"
- android:pathData="M79,19L79,89"
- android:strokeColor="#33FFFFFF"
- android:strokeWidth="0.8" />
+ android:viewportWidth="108"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#3DDC84"
+ android:pathData="M0,0h108v108h-108z"/>
+ <path android:fillColor="#00000000" android:pathData="M9,0L9,108"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M19,0L19,108"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M29,0L29,108"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M39,0L39,108"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M49,0L49,108"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M59,0L59,108"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M69,0L69,108"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M79,0L79,108"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M89,0L89,108"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M99,0L99,108"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M0,9L108,9"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M0,19L108,19"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M0,29L108,29"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M0,39L108,39"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M0,49L108,49"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M0,59L108,59"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M0,69L108,69"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M0,79L108,79"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M0,89L108,89"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M0,99L108,99"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M19,29L89,29"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M19,39L89,39"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M19,49L89,49"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M19,59L89,59"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M19,69L89,69"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M19,79L89,79"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M29,19L29,89"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M39,19L39,89"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M49,19L49,89"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M59,19L59,89"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M69,19L69,89"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+ <path android:fillColor="#00000000" android:pathData="M79,19L79,89"
+ android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_foreground.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..e773727
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+<!--
+ Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108"
+ android:tint="#FFFFFF">
+ <group android:scaleX="1.9575"
+ android:scaleY="1.9575"
+ android:translateX="30.51"
+ android:translateY="30.51">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
+ </group>
+</vector>
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_outline_info_24.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_outline_info_24.xml
new file mode 100644
index 0000000..0510f56
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_outline_info_24.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector android:height="24dp" android:tint="#FFFFFF"
+ android:viewportHeight="24" android:viewportWidth="24"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="@android:color/white" android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
+</vector>
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_info_panel.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_info_panel.xml
new file mode 100644
index 0000000..af0aa020
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_info_panel.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2020 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+ android:opacity="translucent">
+ <item xmlns:android="http://schemas.android.com/apk/res/android">
+ <shape
+ android:shape="rectangle">
+ <solid
+ android:width="3dp"
+ android:color="@color/cameraPipeThemeBgOverlayDark100"/>
+ <corners
+ android:bottomLeftRadius="12dp"
+ android:bottomRightRadius="12dp"
+ android:topLeftRadius="12dp"
+ android:topRightRadius="12dp"/>
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_launch_screen.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_launch_screen.xml
index cc087fe..902e878 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_launch_screen.xml
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_launch_screen.xml
@@ -1,4 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?><!--
+<?xml version="1.0" encoding="utf-8"?>
+<!--
Copyright 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button.xml
new file mode 100644
index 0000000..a23f88b
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2020 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="true"
+ android:drawable="@drawable/theme_round_button_default" />
+ <item android:state_enabled="false"
+ android:drawable="@drawable/theme_round_button_disabled" />
+</selector>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_default.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_default.xml
new file mode 100644
index 0000000..d7dcfb7
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_default.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2020 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.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/cameraPipeThemeBtnOverlay200">
+ <item>
+ <shape
+ android:padding="8dp"
+ android:shape="rectangle">
+ <corners
+ android:bottomLeftRadius="25dp"
+ android:bottomRightRadius="25dp"
+ android:topLeftRadius="25dp"
+ android:topRightRadius="25dp" />
+ <padding
+ android:bottom="6dp"
+ android:left="20dp"
+ android:right="20dp"
+ android:top="6dp" />
+ <solid
+ android:width="3dp"
+ android:color="@color/cameraPipeThemeBtnOverlay100" />
+ </shape>
+ </item>
+</ripple>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_disabled.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_disabled.xml
new file mode 100644
index 0000000..56994f4
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_disabled.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2020 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:padding="8dp"
+ android:shape="rectangle"
+ android:color="@color/cameraPipeThemeBtnOverlay100">
+ <solid
+ android:width="3dp"
+ android:color="@color/cameraPipeThemeBtnOverlay100" />
+ <padding
+ android:bottom="6dp"
+ android:left="20dp"
+ android:right="20dp"
+ android:top="6dp" />
+ <corners
+ android:bottomLeftRadius="25dp"
+ android:bottomRightRadius="25dp"
+ android:topLeftRadius="25dp"
+ android:topRightRadius="25dp" />
+</shape>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_record.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_record.xml
new file mode 100644
index 0000000..f7a80b1
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_record.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2020 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.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/cameraPipeThemeBgRecord">
+ <item>
+ <shape
+ android:padding="8dp"
+ android:shape="rectangle">
+ <solid
+ android:width="3dp"
+ android:color="@color/cameraPipeThemeBgRecordRipple"/>
+ <padding
+ android:bottom="6dp"
+ android:left="20dp"
+ android:right="20dp"
+ android:top="6dp"/>
+ <corners
+ android:bottomLeftRadius="25dp"
+ android:bottomRightRadius="25dp"
+ android:topLeftRadius="25dp"
+ android:topRightRadius="25dp"/>
+ </shape>
+ </item>
+</ripple>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/layout/activity_main.xml b/camera/integration-tests/camerapipetestapp/src/main/res/layout/activity_main.xml
index 8767f7d..bcfe4ef 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/layout/activity_main.xml
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/layout/activity_main.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,49 +12,153 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/cameraPipeThemeBgDark100"
- android:keepScreenOn="true"
- tools:context=".CameraPipeActivity">
-
- <androidx.camera.integration.camera2.pipe.Viewfinder
- android:id="@+id/viewfinder"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="#FFFFFF" />
+ android:keepScreenOn="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:weightSum="2">
+ android:baselineAligned="false"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:id="@+id/key_values"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:gravity="center"
+ android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
- android:layout_marginLeft="20dp"
- android:background="@drawable/graph_background"
android:layout_weight="1"
- android:layout_width="0dp" />
-
+ android:background="@drawable/graph_background"
+ android:gravity="center"
+ android:orientation="vertical" />
<LinearLayout
android:id="@+id/graphs"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:gravity="center"
- android:layout_marginTop="20dp"
android:layout_marginHorizontal="20dp"
- android:layout_weight="1"/>
-
+ android:layout_marginTop="20dp"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical" />
</LinearLayout>
-</FrameLayout>
+
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:fitsSystemWindows="true"
+ app:layout_constraintBottom_toTopOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <androidx.camera.integration.camera2.pipe.Viewfinder
+ android:id="@+id/viewfinder"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="#FFFFFF"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <ImageButton
+ android:id="@+id/capture_button"
+ android:layout_width="150dp"
+ android:layout_height="48dp"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginStart="8dp"
+ android:layout_marginTop="16dp"
+ android:adjustViewBounds="false"
+ android:background="@drawable/theme_round_button"
+ android:src="@drawable/ic_baseline_photo_camera_24"
+ android:visibility="visible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <ImageButton
+ android:id="@+id/switch_button"
+ android:layout_width="72dp"
+ android:layout_height="48dp"
+ android:layout_marginEnd="8dp"
+ android:background="@drawable/theme_round_button"
+ android:src="@drawable/ic_baseline_flip_camera_android_24"
+ app:layout_constraintEnd_toStartOf="@+id/capture_button"
+ app:layout_constraintTop_toTopOf="@+id/capture_button" />
+
+ <ImageButton
+ android:id="@+id/info_button"
+ android:layout_width="72dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="8dp"
+ android:background="@drawable/theme_round_button"
+ android:src="@drawable/ic_outline_info_24"
+ app:layout_constraintStart_toEndOf="@+id/capture_button"
+ app:layout_constraintTop_toTopOf="@+id/capture_button" />
+
+ <ScrollView
+ android:id="@+id/info_view"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginBottom="8dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginStart="8dp"
+ android:layout_marginTop="8dp"
+ android:background="@drawable/theme_info_panel"
+ android:clipToPadding="true"
+ android:fillViewport="true"
+ android:scrollbarStyle="insideOverlay"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <LinearLayout
+ android:id="@+id/info_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/info_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="8dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginStart="8dp"
+ android:layout_marginTop="8dp"
+ android:textColor="@color/cameraPipeThemeFgLight800"
+ android:textSize="10sp"
+ android:typeface="monospace" />
+ </LinearLayout>
+ </ScrollView>
+
+ <TextView
+ android:id="@+id/viewfinder_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="@color/cameraPipeThemeFgOverlay"
+ android:fontFamily="sans-serif-condensed"
+ android:padding="8dp"
+ android:textColor="@color/cameraPipeThemeFgLight800"
+ android:typeface="monospace"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toEndOf="@id/viewfinder"
+ app:layout_constraintStart_toStartOf="@id/viewfinder"
+ app:layout_constraintTop_toTopOf="@id/viewfinder" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
+
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index f763f8a..bbd3e02 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,19 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 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.
--->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
- <background android:drawable="@drawable/ic_launcher_background" />
- <foreground android:drawable="@drawable/ic_launcher_foreground" />
+ <background android:drawable="@drawable/ic_launcher_background"/>
+ <foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index f763f8a..bbd3e02 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,19 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 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.
--->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
- <background android:drawable="@drawable/ic_launcher_background" />
- <foreground android:drawable="@drawable/ic_launcher_foreground" />
+ <background android:drawable="@drawable/ic_launcher_background"/>
+ <foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher.png
index a571e60..349ab41 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher_round.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher_round.png
index 61da551..7614eb4 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher_round.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher.png
index c41dd28..a57c7a8 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher_round.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher_round.png
index db5080a..df0dbb0 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher_round.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher.png
index 6dba46d..ce806bd 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher_round.png
index da31a87..5a7d770 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher_round.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 15ac681..cf7ce7d 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
index b216f2d..4cc2f02 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index f25a419..f37f717 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
index e96783c..e4175ef 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisBaseTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisBaseTest.kt
index 575b05f..580f20a 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisBaseTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisBaseTest.kt
@@ -17,14 +17,16 @@
package androidx.camera.integration.uiwidgets.rotations
import android.content.Intent
+import androidx.camera.core.CameraX
import androidx.camera.testing.CameraUtil
import androidx.camera.testing.CoreAppTestUtil
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.rule.GrantPermissionRule
import androidx.test.uiautomator.UiDevice
import androidx.testutils.withActivity
-import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
import org.junit.Assume
import org.junit.Rule
import org.junit.rules.TestRule
@@ -43,7 +45,11 @@
abstract class ImageAnalysisBaseTest<A : CameraActivity> {
@get:Rule
- val mUseCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+ val mUseCameraRule: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+
+ @get:Rule
+ val mCameraActivityRules: GrantPermissionRule =
+ GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
protected val mDevice: UiDevice =
UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@@ -58,6 +64,7 @@
}
protected fun tearDown() {
+ CameraX.shutdown().get()
mDevice.unfreezeRotation()
}
@@ -84,7 +91,12 @@
val (sensorToTargetRotation, imageRotationDegrees) = scenario.withActivity {
Pair(getSensorRotationRelativeToAnalysisTargetRotation(), mAnalysisImageRotation)
}
- assertThat(sensorToTargetRotation).isEqualTo(imageRotationDegrees)
+ assertWithMessage(
+ "The image rotation degrees [$imageRotationDegrees] was expected to" +
+ " be equal to [$sensorToTargetRotation]"
+ )
+ .that(imageRotationDegrees)
+ .isEqualTo(sensorToTargetRotation)
}
}
@@ -101,7 +113,9 @@
protected inline fun <reified A : CameraActivity> ActivityScenario<A>.waitOnCameraFrames() {
val analysisRunning = withActivity { mAnalysisRunning }
- assertThat(analysisRunning.tryAcquire(IMAGES_COUNT, TIMEOUT, TimeUnit.SECONDS)).isTrue()
+ assertWithMessage("Timed out waiting on image analysis frames")
+ .that(analysisRunning.tryAcquire(IMAGES_COUNT, TIMEOUT, TimeUnit.SECONDS))
+ .isTrue()
}
protected inline fun <reified A : CameraActivity> ActivityScenario<A>.resetFramesCount() {
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisLockedOrientationTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisLockedOrientationTest.kt
index c81032c..4f4899a 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisLockedOrientationTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisLockedOrientationTest.kt
@@ -19,10 +19,8 @@
import androidx.camera.core.CameraSelector
import androidx.test.core.app.ActivityScenario
import androidx.test.filters.LargeTest
-import androidx.test.rule.GrantPermissionRule
import org.junit.After
import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -49,10 +47,6 @@
}
}
- @get:Rule
- val mCameraPermissionRule: GrantPermissionRule =
- GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
-
@Before
fun before() {
setUp(lensFacing)
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisOrientationConfigChangesTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisOrientationConfigChangesTest.kt
index 97e96d6..085988b 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisOrientationConfigChangesTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisOrientationConfigChangesTest.kt
@@ -22,12 +22,10 @@
import androidx.test.core.app.ActivityScenario
import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
import androidx.testutils.withActivity
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -55,10 +53,6 @@
}
}
- @get:Rule
- val mCameraPermissionRule: GrantPermissionRule =
- GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
-
@Before
fun before() {
setUp(lensFacing)
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisUnlockedOrientationTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisUnlockedOrientationTest.kt
index 2883dda..82aa20f 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisUnlockedOrientationTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisUnlockedOrientationTest.kt
@@ -21,10 +21,8 @@
import androidx.camera.core.CameraSelector.LENS_FACING_FRONT
import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
import org.junit.After
import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -50,10 +48,6 @@
}
}
- @get:Rule
- val mCameraPermissionRule: GrantPermissionRule =
- GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
-
@Before
fun before() {
setUp(lensFacing)
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureBaseTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureBaseTest.kt
index 824109f..fb98edb 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureBaseTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureBaseTest.kt
@@ -21,15 +21,18 @@
import android.os.Environment
import android.view.View
import androidx.camera.core.CameraSelector
+import androidx.camera.core.CameraX
import androidx.camera.integration.uiwidgets.R
import androidx.camera.testing.CameraUtil
import androidx.camera.testing.CoreAppTestUtil
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.rule.GrantPermissionRule
import androidx.test.uiautomator.UiDevice
import androidx.testutils.withActivity
import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
import org.junit.Rule
@@ -51,7 +54,11 @@
abstract class ImageCaptureBaseTest<A : CameraActivity> {
@get:Rule
- val mUseCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+ val mUseCameraRule: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+
+ @get:Rule
+ val mCameraActivityRules: GrantPermissionRule =
+ GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
protected val mDevice: UiDevice =
UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@@ -76,6 +83,7 @@
}
protected fun tearDown() {
+ CameraX.shutdown().get()
mDevice.unfreezeRotation()
}
@@ -135,7 +143,13 @@
}
val areResolutionsEqual = expectedResolution == imageSize
- assertThat(areRotationsEqual || areResolutionsEqual).isTrue()
+ assertWithMessage(
+ "The captured image rotation degrees [$imageRotationDegrees] was expected to be " +
+ "equal to [$sensorToTargetRotation], or the captured image's resolution " +
+ "[$imageSize] was expected to be equal to [$expectedResolution]"
+ )
+ .that(areRotationsEqual || areResolutionsEqual)
+ .isTrue()
// Delete captured image
scenario.withActivity { mCaptureResult?.delete() ?: Unit }
@@ -158,7 +172,9 @@
protected inline fun <reified A : CameraActivity> ActivityScenario<A>.waitOnCameraFrames() {
val analysisRunning = withActivity { mAnalysisRunning }
- assertThat(analysisRunning.tryAcquire(IMAGES_COUNT, TIMEOUT, TimeUnit.SECONDS)).isTrue()
+ assertWithMessage("Timed out waiting on image analysis frames")
+ .that(analysisRunning.tryAcquire(IMAGES_COUNT, TIMEOUT, TimeUnit.SECONDS))
+ .isTrue()
}
protected inline fun <reified A : CameraActivity> ActivityScenario<A>.resetFramesCount() {
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureLockedOrientationTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureLockedOrientationTest.kt
index da68c27..696972a 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureLockedOrientationTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureLockedOrientationTest.kt
@@ -18,10 +18,8 @@
import androidx.test.core.app.ActivityScenario
import androidx.test.filters.LargeTest
-import androidx.test.rule.GrantPermissionRule
import org.junit.After
import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -49,10 +47,6 @@
}
}
- @get:Rule
- val mCameraPermissionRule: GrantPermissionRule =
- GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
-
@Before
fun before() {
setUp(lensFacing)
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureOrientationConfigChangesTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureOrientationConfigChangesTest.kt
index 3c3b3a3..abc055c 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureOrientationConfigChangesTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureOrientationConfigChangesTest.kt
@@ -21,12 +21,10 @@
import androidx.test.core.app.ActivityScenario
import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
import androidx.testutils.withActivity
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -61,10 +59,6 @@
}
}
- @get:Rule
- val mCameraPermissionRule: GrantPermissionRule =
- GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
-
@Before
fun before() {
setUp(lensFacing)
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureUnlockedOrientationTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureUnlockedOrientationTest.kt
index 95bcbf0..0248f11 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureUnlockedOrientationTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureUnlockedOrientationTest.kt
@@ -24,10 +24,8 @@
import androidx.camera.integration.uiwidgets.rotations.CameraActivity.Companion.IMAGE_CAPTURE_MODE_OUTPUT_STREAM
import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
import org.junit.After
import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -84,10 +82,6 @@
}
}
- @get:Rule
- val mCameraPermissionRule: GrantPermissionRule =
- GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
-
@Before
fun before() {
setUp(lensFacing)
diff --git a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
index 8b16ab1..114f84c 100644
--- a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
+++ b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
@@ -16,9 +16,16 @@
package androidx.camera.integration.view
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Matrix
+import android.graphics.PointF
import android.net.Uri
+import android.os.Build
+import android.view.Surface
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
+import androidx.camera.core.impl.utils.Exif
import androidx.camera.testing.CameraUtil
import androidx.camera.view.PreviewView
import androidx.fragment.app.testing.FragmentScenario
@@ -31,7 +38,10 @@
import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
+import com.google.common.collect.ImmutableList
import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Assume
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
@@ -49,6 +59,13 @@
@RunWith(AndroidJUnit4::class)
class CameraControllerFragmentTest {
+ companion object {
+ // The right shift needed to get color component from a Int color, in the order of R, G
+ // and B.
+ private val RGB_SHIFTS = ImmutableList.of(/*R*/16, /*G*/ 8, /*B*/0)
+ private const val COLOR_MASK = 0xFF
+ }
+
@get:Rule
val thrown: ExpectedException = ExpectedException.none()
@@ -64,6 +81,61 @@
private val instrumentation = InstrumentationRegistry.getInstrumentation()
@Test
+ fun capturedImage_sameAsPreviewSnapshot() {
+ // TODO(b/147448711) Add back in once cuttlefish has correct user cropping functionality.
+ Assume.assumeFalse(
+ "Cuttlefish does not correctly handle crops. Unable to test.",
+ Build.MODEL.contains("Cuttlefish")
+ )
+
+ // Arrange.
+ val fragment = createFragmentScenario().getFragment()
+ fragment.assertPreviewIsStreaming()
+ // Scaled down images to 10x10 bitmap to normalize and reduce computation.
+ val width = 10
+ val height = 10
+
+ // Act.
+ // Get the capture bitmap and the preview bitmap.
+ val captureTargetDegrees = rotationValueToRotationDegrees(fragment.accelerometerRotation)
+ val captureResult = fragment.assertCanTakePicture()
+ var captureBitmap = Bitmap.createScaledBitmap(captureResult.first, width, height, true)
+ val captureDegrees = captureResult.second
+
+ val previewTargetDegrees =
+ rotationValueToRotationDegrees(fragment.previewView.display.rotation)
+ var previewBitmap = fragment.previewView.bitmap!!
+ previewBitmap = Bitmap.createScaledBitmap(previewBitmap, width, height, true)
+
+ // Rotate capture bitmap to match preview orientation
+ val captureToPreviewDegrees = captureTargetDegrees - previewTargetDegrees + captureDegrees
+ val rotateCapture = Matrix()
+ rotateCapture.postRotate(
+ captureToPreviewDegrees.toFloat(),
+ width.toFloat() / 2,
+ height.toFloat() / 2
+ )
+ captureBitmap = Bitmap.createBitmap(captureBitmap, 0, 0, width, height, rotateCapture, true)
+
+ // Assert.
+ val captureMoment = getRgbMoments(captureBitmap)
+ val previewMoment = getRgbMoments(previewBitmap)
+ // For a 10x10 image, we allow an 1px error. The 2 bitmaps are different due to
+ // dynamic range processing, especially in a high contrast environment. The error
+ // tolerance is purposely high to avoid false positive.
+ val errorTolerance = 1F
+ for ((i, colorShift) in RGB_SHIFTS.withIndex()) {
+ val errorMsg = "Color $i Capture\n" +
+ colorComponentToReadableString(captureBitmap, colorShift) + "Preview\n" +
+ colorComponentToReadableString(previewBitmap, colorShift)
+ assertWithMessage(errorMsg).that(captureMoment[i].x).isWithin(errorTolerance)
+ .of(previewMoment[i].x)
+ assertWithMessage(errorMsg).that(captureMoment[i].y).isWithin(errorTolerance)
+ .of(previewMoment[i].y)
+ }
+ }
+
+ @Test
fun fragmentLaunched_canTakePicture() {
val fragment = createFragmentScenario().getFragment()
fragment.assertPreviewIsStreaming()
@@ -132,11 +204,71 @@
}
/**
+ * Calculates the 1st order moment (center of mass) of the R, G and B of the bitmap.
+ */
+ private fun getRgbMoments(bitmap: Bitmap): Array<PointF> {
+ val rgbMoments = arrayOf(PointF(0F, 0F), PointF(0F, 0F), PointF(0F, 0F))
+ val totals = arrayOf(0F, 0F, 0F)
+ for ((i, colorShift) in RGB_SHIFTS.withIndex()) {
+ for (x in 0 until bitmap.width) {
+ for (y in 0 until bitmap.height) {
+ val color = bitmap.getPixel(x, y)
+ val colorComponent = color shr colorShift and COLOR_MASK
+ rgbMoments[i].x += colorComponent * x
+ rgbMoments[i].y += colorComponent * y
+ totals[i] += colorComponent.toFloat()
+ }
+ }
+ rgbMoments[i].x /= totals[i]
+ rgbMoments[i].y /= totals[i]
+ }
+ return rgbMoments
+ }
+
+ /**
+ * Converts the R, G or B component of the bitmap to a readable string table with fixed
+ * column width.
+ *
+ * <p> Example:
+ * <pre>
+ * 255 255 200
+ * 200 10 100
+ * 0 1 10
+ * </pre>
+ *
+ * @param colorShift: color component in the format of right shift on Int color.
+ */
+ private fun colorComponentToReadableString(bitmap1: Bitmap, colorShift: Int):
+ String {
+ var result = ""
+ for (x in 0 until bitmap1.width) {
+ for (y in 0 until bitmap1.height) {
+ var color = (bitmap1.getPixel(x, y) shr colorShift and 0xFF).toString()
+ // 10x10 table Each column is a fixed size of 4.
+ color += " ".repeat((3 - color.length))
+ result += "$color "
+ }
+ result += "\n"
+ }
+ return result
+ }
+
+ private fun rotationValueToRotationDegrees(rotationValue: Int): Int {
+ return when (rotationValue) {
+ Surface.ROTATION_0 -> 0
+ Surface.ROTATION_90 -> 90
+ Surface.ROTATION_180 -> 180
+ Surface.ROTATION_270 -> 270
+ else -> throw IllegalStateException("Unexpected rotation value $rotationValue")
+ }
+ }
+
+ /**
* Takes a picture and assert the URI exists.
*
* <p> Also cleans up the saved picture afterwards.
*/
- private fun CameraControllerFragment.assertCanTakePicture() {
+ private fun CameraControllerFragment.assertCanTakePicture(): Pair<Bitmap, Int> {
val imageCallbackSemaphore = Semaphore(0)
var uri: Uri? = null
instrumentation.runOnMainSync {
@@ -152,9 +284,19 @@
})
}
assertThat(imageCallbackSemaphore.tryAcquire(TIMEOUT_SECONDS, TimeUnit.SECONDS)).isTrue()
- assertThat(uri).isNotNull()
+
+ // Read bitmap and exif rotation to return.
+ val bitmap = this.activity!!.contentResolver.openInputStream(uri!!)!!.use {
+ BitmapFactory.decodeStream(it)
+ }
+ val rotationDegrees = this.activity!!.contentResolver.openInputStream(uri!!)!!.use {
+ val exif = Exif.createFromInputStream(it)
+ exif.rotation
+ }
+
// Delete the saved picture. Assert 1 row was deleted.
assertThat(this.activity!!.contentResolver.delete(uri!!, null, null)).isEqualTo(1)
+ return Pair(bitmap, rotationDegrees)
}
private fun createFragmentScenario(): FragmentScenario<CameraControllerFragment?> {
@@ -185,7 +327,7 @@
private fun CameraControllerFragment.assertPreviewState(state: PreviewView.StreamState) {
val previewStreaming = Semaphore(0)
instrumentation.runOnMainSync {
- this.observePreviewStreamState(Observer {
+ previewView.previewStreamState.observe(this, Observer {
if (it == state) {
previewStreaming.release()
}
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
index 668aedb..778612f9 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
@@ -46,10 +46,10 @@
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.impl.utils.futures.FutureCallback;
import androidx.camera.core.impl.utils.futures.Futures;
+import androidx.camera.view.AccelerometerRotationListener;
import androidx.camera.view.LifecycleCameraController;
import androidx.camera.view.PreviewView;
import androidx.fragment.app.Fragment;
-import androidx.lifecycle.Observer;
import com.google.common.util.concurrent.ListenableFuture;
@@ -69,7 +69,8 @@
@SuppressWarnings("WeakerAccess")
LifecycleCameraController mCameraController;
- private PreviewView mPreviewView;
+ @VisibleForTesting
+ PreviewView mPreviewView;
private FrameLayout mContainer;
private Button mFlashMode;
private ToggleButton mCameraToggle;
@@ -79,6 +80,7 @@
private ToggleButton mTapToFocusToggle;
private TextView mZoomStateText;
private TextView mTorchStateText;
+ private RotationListener mAccelerometerRotationListener;
@Override
public void onAttach(@NonNull Context context) {
@@ -92,7 +94,9 @@
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
mExecutorService = Executors.newSingleThreadExecutor();
- mCameraController = new LifecycleCameraController(getContext());
+ mAccelerometerRotationListener = new RotationListener(requireContext());
+ mAccelerometerRotationListener.enable();
+ mCameraController = new LifecycleCameraController(requireContext());
mCameraController.bindToLifecycle(getViewLifecycleOwner());
View view = inflater.inflate(R.layout.camera_controller_view, container, false);
@@ -270,6 +274,7 @@
if (mExecutorService != null) {
mExecutorService.shutdown();
}
+ mAccelerometerRotationListener.disable();
}
void logFailedFuture(ListenableFuture<Void> voidFuture) {
@@ -351,6 +356,27 @@
// -----------------
/**
+ * Listens to accelerometer rotation change and pass it to tests.
+ */
+ static class RotationListener extends AccelerometerRotationListener {
+
+ private int mRotation;
+
+ RotationListener(@NonNull Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onRotationChanged(int rotation) {
+ mRotation = rotation;
+ }
+
+ int getRotation() {
+ return mRotation;
+ }
+ }
+
+ /**
* @hide
*/
@RestrictTo(RestrictTo.Scope.TESTS)
@@ -362,9 +388,16 @@
* @hide
*/
@RestrictTo(RestrictTo.Scope.TESTS)
- void observePreviewStreamState(Observer<PreviewView.StreamState> observer) {
- mPreviewView.getPreviewStreamState().observe(CameraControllerFragment.this,
- observer);
+ PreviewView getPreviewView() {
+ return mPreviewView;
+ }
+
+ /**
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.TESTS)
+ int getAccelerometerRotation() {
+ return mAccelerometerRotationListener.getRotation();
}
@VisibleForTesting
diff --git a/camera/integration-tests/viewtestapp/src/main/res/layout-land/camera_controller_view.xml b/camera/integration-tests/viewtestapp/src/main/res/layout-land/camera_controller_view.xml
new file mode 100644
index 0000000..1d646ac
--- /dev/null
+++ b/camera/integration-tests/viewtestapp/src/main/res/layout-land/camera_controller_view.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <FrameLayout
+ android:id="@+id/container"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+ <androidx.camera.view.PreviewView
+ android:id="@+id/preview_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <Button
+ android:id="@+id/remove_or_add"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/btn_remove_or_add" />
+ <Button
+ android:id="@+id/shrink"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/btn_shrink" />
+ <ToggleButton
+ android:id="@+id/camera_toggle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textOff="@string/toggle_camera_front"
+ android:textOn="@string/toggle_camera_back" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <ToggleButton
+ android:id="@+id/capture_enabled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textOff="@string/toggle_capture_disabled"
+ android:textOn="@string/toggle_capture_enabled" />
+ <Button
+ android:id="@+id/flash_mode"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <Button
+ android:id="@+id/capture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/btn_capture" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <ToggleButton
+ android:id="@+id/video_enabled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textOff="@string/toggle_video_disabled"
+ android:textOn="@string/toggle_video_enabled" />
+ <Button
+ android:id="@+id/video_record"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/btn_video_record" />
+ <Button
+ android:id="@+id/video_stop_recording"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/btn_video_stop_recording"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="40dp"
+ android:gravity="center_vertical">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/linear_zoom"/>
+ <SeekBar
+ android:id="@+id/linear_zoom_slider"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:max="100"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <ToggleButton
+ android:id="@+id/pinch_to_zoom_toggle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textOff="@string/pinch_to_zoom"
+ android:textOn="@string/pinch_to_zoom"/>
+ <ToggleButton
+ android:id="@+id/tap_to_focus_toggle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textOff="@string/tap_to_focus"
+ android:textOn="@string/tap_to_focus"/>
+ <ToggleButton
+ android:id="@+id/torch_toggle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textOff="@string/torch"
+ android:textOn="@string/torch"/>
+ </LinearLayout>
+ <TextView
+ android:id="@+id/zoom_state_text"
+ android:layout_width="300dp"
+ android:layout_height="wrap_content"
+ android:lines="2"/>
+ <TextView
+ android:id="@+id/torch_state_text"
+ android:layout_width="300dp"
+ android:layout_height="wrap_content"/>
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/compose/androidview/androidview/build.gradle b/compose/androidview/androidview/build.gradle
index 5eb8028..db6fb8f 100644
--- a/compose/androidview/androidview/build.gradle
+++ b/compose/androidview/androidview/build.gradle
@@ -27,7 +27,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
// TODO: remove / refactor out reflection dependencies, this is a large dependency to bundle
// with a library.
diff --git a/compose/androidview/androidview/integration-tests/androidview-demos/build.gradle b/compose/androidview/androidview/integration-tests/androidview-demos/build.gradle
index 4348e4d..6523313 100644
--- a/compose/androidview/androidview/integration-tests/androidview-demos/build.gradle
+++ b/compose/androidview/androidview/integration-tests/androidview-demos/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/animation/animation-core/build.gradle b/compose/animation/animation-core/build.gradle
index 83e859d..a6edcb2 100644
--- a/compose/animation/animation-core/build.gradle
+++ b/compose/animation/animation-core/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/compose/animation/animation-core/samples/build.gradle b/compose/animation/animation-core/samples/build.gradle
index 0217f4e..49c9294 100644
--- a/compose/animation/animation-core/samples/build.gradle
+++ b/compose/animation/animation-core/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/animation/animation/build.gradle b/compose/animation/animation/build.gradle
index bcea23f..580b930 100644
--- a/compose/animation/animation/build.gradle
+++ b/compose/animation/animation/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/compose/animation/animation/integration-tests/animation-demos/build.gradle b/compose/animation/animation/integration-tests/animation-demos/build.gradle
index 2b167ff..5892c7e 100644
--- a/compose/animation/animation/integration-tests/animation-demos/build.gradle
+++ b/compose/animation/animation/integration-tests/animation-demos/build.gradle
@@ -10,7 +10,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
index 2e16ef8..b71c71b 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
@@ -65,14 +65,16 @@
val shortText = "Click me"
val longText = "Very long text\nthat spans across\nmultiple lines"
var short by remember { mutableStateOf(true) }
- Box(modifier = Modifier
- .background(Color.Blue,
- RoundedCornerShape(15.dp)
- )
- .clickable { short = !short }
- .padding(20.dp)
- .wrapContentSize()
- .animateContentSize { startSize, endSize -> println("$startSize -> $endSize") }
+ Box(
+ modifier = Modifier
+ .background(
+ Color.Blue,
+ RoundedCornerShape(15.dp)
+ )
+ .clickable { short = !short }
+ .padding(20.dp)
+ .wrapContentSize()
+ .animateContentSize { startSize, endSize -> println("$startSize -> $endSize") }
) {
Text(
if (short) {
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
index 7b46d6f..5a3254f 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
@@ -72,10 +72,12 @@
Stack(
Modifier.padding(bottom = 20.dp)
) {
- Button(modifier = Modifier.align(Alignment.TopEnd).padding(10.dp),
+ Button(
+ modifier = Modifier.align(Alignment.TopEnd).padding(10.dp),
onClick = {
counter = (counter + 1) % 12
- }) {
+ }
+ ) {
Text("Click Me")
}
@@ -89,7 +91,7 @@
Item(
pastelColors[0],
"Expand Vertically + Fade In\nShrink " +
- "Vertically + Fade Out\n(Column Default)"
+ "Vertically + Fade Out\n(Column Default)"
)
}
HorizontalTransition(visible = itemNum > 1) {
@@ -97,8 +99,9 @@
}
SlideTransition(visible = itemNum > 2) {
Item(
- pastelColors[2], "Slide In Horizontally + Fade In\nSlide Out Horizontally + " +
- "Fade Out"
+ pastelColors[2],
+ "Slide In Horizontally + Fade In\nSlide Out Horizontally + " +
+ "Fade Out"
)
}
AnimatedVisibility(
@@ -113,8 +116,9 @@
}
FullyLoadedTransition(visible = itemNum > 5) {
Item(
- pastelColors[0], "Expand Vertically + Fade In + Slide In Vertically\n" +
- "Shrink Vertically + Fade Out + Slide Out Vertically"
+ pastelColors[0],
+ "Expand Vertically + Fade In + Slide In Vertically\n" +
+ "Shrink Vertically + Fade Out + Slide Out Vertically"
)
}
}
@@ -210,7 +214,8 @@
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun FullyLoadedTransition(visible: Boolean, children: @Composable () -> Unit) {
- AnimatedVisibility(visible = visible,
+ AnimatedVisibility(
+ visible = visible,
enter = slideInVertically(
// Start the slide from 40 (pixels) above where the content is supposed to go, to
// produce a parallax effect
@@ -218,7 +223,8 @@
) + expandVertically(
expandFrom = Alignment.Top
) + fadeIn(initialAlpha = 0.3f),
- exit = slideOutVertically() + shrinkVertically() + fadeOut()) {
+ exit = slideOutVertically() + shrinkVertically() + fadeOut()
+ ) {
children()
}
}
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt
index 84e84fc..6b825a9 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt
@@ -72,9 +72,10 @@
}
}
- Button({
- itemNum = 0
- }, modifier = Modifier.align(End).padding(15.dp)) {
+ Button(
+ { itemNum = 0 },
+ modifier = Modifier.align(End).padding(15.dp)
+ ) {
Text("Clear All")
}
}
@@ -87,4 +88,4 @@
Color(0xffBCF8FF),
Color(0xff8AEAE9),
Color(0xff46CECA)
-)
\ No newline at end of file
+)
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
index 77e570c..8d93ddd 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
@@ -19,20 +19,27 @@
import androidx.compose.integration.demos.common.ComposableDemo
import androidx.compose.integration.demos.common.DemoCategory
-val AnimationDemos = DemoCategory("Animation", listOf(
- ComposableDemo("Animate multi-dimensional prop") { MultiDimensionalAnimationDemo() },
- ComposableDemo("Animate") { SingleValueAnimationDemo() },
- ComposableDemo("Animated scrolling") { FancyScrollingDemo() },
- ComposableDemo("Animate Content Size") { AnimateContentSizeDemo() },
- ComposableDemo("Animate Visibility Demo") { AnimatedVisibilityDemo() },
- ComposableDemo("Animate Visibility Lazy Column Demo") { AnimatedVisibilityLazyColumnDemo() },
- ComposableDemo("Cross Fade") { CrossfadeDemo() },
- ComposableDemo("Enter/Exit Transition Demo") { EnterExitTransitionDemo() },
- ComposableDemo("Gesture based animation") { GestureBasedAnimationDemo() },
- ComposableDemo("Manual animation clock") { AnimatableSeekBarDemo() },
- ComposableDemo("Repeating rotation") { RepeatedRotationDemo() },
- ComposableDemo("Spring back scrolling") { SpringBackScrollingDemo() },
- ComposableDemo("State animation with interruptions") { StateAnimationWithInterruptionsDemo() },
- ComposableDemo("State based ripple") { StateBasedRippleDemo() },
- ComposableDemo("Swipe to dismiss") { SwipeToDismissDemo() }
-))
+val AnimationDemos = DemoCategory(
+ "Animation",
+ listOf(
+ ComposableDemo("Animate multi-dimensional prop") { MultiDimensionalAnimationDemo() },
+ ComposableDemo("Animate") { SingleValueAnimationDemo() },
+ ComposableDemo("Animated scrolling") { FancyScrollingDemo() },
+ ComposableDemo("Animate Content Size") { AnimateContentSizeDemo() },
+ ComposableDemo("Animate Visibility Demo") { AnimatedVisibilityDemo() },
+ ComposableDemo("Animate Visibility Lazy Column Demo") {
+ AnimatedVisibilityLazyColumnDemo()
+ },
+ ComposableDemo("Cross Fade") { CrossfadeDemo() },
+ ComposableDemo("Enter/Exit Transition Demo") { EnterExitTransitionDemo() },
+ ComposableDemo("Gesture based animation") { GestureBasedAnimationDemo() },
+ ComposableDemo("Manual animation clock") { AnimatableSeekBarDemo() },
+ ComposableDemo("Repeating rotation") { RepeatedRotationDemo() },
+ ComposableDemo("Spring back scrolling") { SpringBackScrollingDemo() },
+ ComposableDemo("State animation with interruptions") {
+ StateAnimationWithInterruptionsDemo()
+ },
+ ComposableDemo("State based ripple") { StateBasedRippleDemo() },
+ ComposableDemo("Swipe to dismiss") { SwipeToDismissDemo() }
+ )
+)
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/CrossfadeDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/CrossfadeDemo.kt
index fd214c8..dc6b702 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/CrossfadeDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/CrossfadeDemo.kt
@@ -41,10 +41,12 @@
Row {
tabs.forEach { tab ->
Box(
- Modifier.tapGestureFilter(onTap = {
- Log.e("Crossfade", "Switch to $tab")
- current = tab
- })
+ Modifier.tapGestureFilter(
+ onTap = {
+ Log.e("Crossfade", "Switch to $tab")
+ current = tab
+ }
+ )
.weight(1f, true)
.preferredHeight(48.dp),
backgroundColor = tab.color
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt
index 1a62aa5..b9bbd03 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt
@@ -76,59 +76,83 @@
var visible by remember { mutableStateOf(true) }
val (selectedOption, onOptionSelected) = remember { mutableStateOf(0) }
Column(Modifier.fillMaxSize()) {
- Button(modifier = Modifier.align(CenterHorizontally), onClick = {
- alignment = TopCenter
- visible = !visible
- }) {
+ Button(
+ modifier = Modifier.align(CenterHorizontally),
+ onClick = {
+ alignment = TopCenter
+ visible = !visible
+ }
+ ) {
Text("Top")
}
Row(Modifier.fillMaxWidth().weight(1f)) {
Stack(Modifier.fillMaxHeight().wrapContentWidth()) {
- Button(modifier = Modifier.align(TopEnd), onClick = {
- alignment = TopStart
- visible = !visible
- }) {
+ Button(
+ modifier = Modifier.align(TopEnd),
+ onClick = {
+ alignment = TopStart
+ visible = !visible
+ }
+ ) {
Text("Top\nStart")
}
- Button(modifier = Modifier.align(CenterEnd), onClick = {
- alignment = CenterStart
- visible = !visible
- }) {
+ Button(
+ modifier = Modifier.align(CenterEnd),
+ onClick = {
+ alignment = CenterStart
+ visible = !visible
+ }
+ ) {
Text("Start")
}
- Button(modifier = Modifier.align(BottomEnd), onClick = {
- alignment = BottomStart
- visible = !visible
- }) {
+ Button(
+ modifier = Modifier.align(BottomEnd),
+ onClick = {
+ alignment = BottomStart
+ visible = !visible
+ }
+ ) {
Text("Bottom\nStart")
}
}
CenterMenu(selectedOption, oppositeAlignment.value, alignment, visible)
Stack(Modifier.fillMaxHeight().wrapContentWidth()) {
- Button(modifier = Modifier.align(TopStart), onClick = {
- alignment = TopEnd
- visible = !visible
- }) {
+ Button(
+ modifier = Modifier.align(TopStart),
+ onClick = {
+ alignment = TopEnd
+ visible = !visible
+ }
+ ) {
Text("Top\nEnd")
}
- Button(modifier = Modifier.align(CenterStart), onClick = {
- alignment = CenterEnd
- visible = !visible
- }) {
+ Button(
+ modifier = Modifier.align(CenterStart),
+ onClick = {
+ alignment = CenterEnd
+ visible = !visible
+ }
+ ) {
Text("End")
}
- Button(modifier = Modifier.align(BottomEnd), onClick = {
- alignment = BottomEnd
- visible = !visible
- }) {
+ Button(
+ modifier = Modifier.align(BottomEnd),
+ onClick = {
+ alignment = BottomEnd
+ visible = !visible
+ }
+ ) {
Text("Bottom\nEnd")
}
}
}
- Button(modifier = Modifier.align(CenterHorizontally), onClick = {
- alignment = BottomCenter
- visible = !visible
- }) {
+ Button(
+ modifier = Modifier.align(CenterHorizontally),
+ onClick = {
+ alignment = BottomCenter
+ visible = !visible
+ }
+ ) {
Text("Bottom")
}
@@ -220,14 +244,15 @@
val radioOptions =
listOf("No Fade", "Fade In", "Fade Out", "Fade In & Fade out")
radioOptions.forEachIndexed { i, text ->
- Row(Modifier
- .fillMaxWidth()
- .preferredHeight(30.dp)
- .selectable(
- selected = (i == selectedOption),
- onClick = { onOptionSelected(i) }
- )
- .padding(horizontal = 16.dp),
+ Row(
+ Modifier
+ .fillMaxWidth()
+ .preferredHeight(30.dp)
+ .selectable(
+ selected = (i == selectedOption),
+ onClick = { onOptionSelected(i) }
+ )
+ .padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/FancyScrollingDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/FancyScrollingDemo.kt
index e15fd885..fae08f1 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/FancyScrollingDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/FancyScrollingDemo.kt
@@ -53,29 +53,36 @@
)
val animScroll = animatedFloat(0f)
val itemWidth = remember { mutableStateOf(0f) }
- val gesture = Modifier.rawDragGestureFilter(dragObserver = object : DragObserver {
- override fun onDrag(dragDistance: Offset): Offset {
- // Snap to new drag position
- animScroll.snapTo(animScroll.value + dragDistance.x)
- return dragDistance
- }
+ val gesture = Modifier.rawDragGestureFilter(
+ dragObserver = object : DragObserver {
+ override fun onDrag(dragDistance: Offset): Offset {
+ // Snap to new drag position
+ animScroll.snapTo(animScroll.value + dragDistance.x)
+ return dragDistance
+ }
- override fun onStop(velocity: Offset) {
+ override fun onStop(velocity: Offset) {
- // Uses default decay animation to calculate where the fling will settle,
- // and adjust that position as needed. The target animation will be used for
- // animating to the adjusted target.
- animScroll.fling(velocity.x, adjustTarget = { target ->
- // Adjust the target position to center align the item
- var rem = target % itemWidth.value
- if (rem < 0) {
- rem += itemWidth.value
- }
- TargetAnimation((target - rem),
- SpringSpec(dampingRatio = 2.0f, stiffness = 100f))
- })
+ // Uses default decay animation to calculate where the fling will settle,
+ // and adjust that position as needed. The target animation will be used for
+ // animating to the adjusted target.
+ animScroll.fling(
+ velocity.x,
+ adjustTarget = { target ->
+ // Adjust the target position to center align the item
+ var rem = target % itemWidth.value
+ if (rem < 0) {
+ rem += itemWidth.value
+ }
+ TargetAnimation(
+ (target - rem),
+ SpringSpec(dampingRatio = 2.0f, stiffness = 100f)
+ )
+ }
+ )
+ }
}
- })
+ )
Canvas(gesture.fillMaxWidth().preferredHeight(400.dp)) {
val width = size.width / 2f
@@ -83,8 +90,9 @@
itemWidth.value = width
if (DEBUG) {
Log.w(
- "Anim", "Drawing items with updated" +
- " AnimatedFloat: ${animScroll.value}"
+ "Anim",
+ "Drawing items with updated" +
+ " AnimatedFloat: ${animScroll.value}"
)
}
drawItems(scroll, width, size.height)
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/GestureBasedAnimationDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/GestureBasedAnimationDemo.kt
index 0d63697..734e749 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/GestureBasedAnimationDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/GestureBasedAnimationDemo.kt
@@ -65,7 +65,8 @@
Modifier.pressIndicatorGestureFilter(
onStart = { toState.value = ComponentState.Pressed },
onStop = { toState.value = ComponentState.Released },
- onCancel = { toState.value = ComponentState.Released })
+ onCancel = { toState.value = ComponentState.Released }
+ )
val state = transition(definition = definition, toState = toState.value)
ScaledColorRect(pressIndicator, scale = state[scale], color = state[color])
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SpringBackScrollingDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SpringBackScrollingDemo.kt
index 9a28732..acc2ae5 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SpringBackScrollingDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SpringBackScrollingDemo.kt
@@ -52,19 +52,24 @@
val animScroll = animatedFloat(0f)
val itemWidth = remember { mutableStateOf(0f) }
val isFlinging = remember { mutableStateOf(false) }
- val gesture = Modifier.rawDragGestureFilter(dragObserver = object : DragObserver {
- override fun onDrag(dragDistance: Offset): Offset {
- animScroll.snapTo(animScroll.targetValue + dragDistance.x)
- return dragDistance
- }
+ val gesture = Modifier.rawDragGestureFilter(
+ dragObserver = object : DragObserver {
+ override fun onDrag(dragDistance: Offset): Offset {
+ animScroll.snapTo(animScroll.targetValue + dragDistance.x)
+ return dragDistance
+ }
- override fun onStop(velocity: Offset) {
- isFlinging.value = true
- animScroll.fling(velocity.x, onEnd = { _, _, _ ->
- isFlinging.value = false
- })
+ override fun onStop(velocity: Offset) {
+ isFlinging.value = true
+ animScroll.fling(
+ velocity.x,
+ onEnd = { _, _, _ ->
+ isFlinging.value = false
+ }
+ )
+ }
}
- })
+ )
Canvas(gesture.fillMaxWidth().preferredHeight(400.dp)) {
itemWidth.value = size.width / 2f
if (isFlinging.value) {
@@ -94,8 +99,9 @@
}
if (DEBUG) {
Log.w(
- "Anim", "Spring back scrolling, redrawing with new" +
- " scroll value: ${animScroll.value}"
+ "Anim",
+ "Spring back scrolling, redrawing with new" +
+ " scroll value: ${animScroll.value}"
)
}
drawRects(animScroll.value)
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt
index d1af27e..cd03e18 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt
@@ -79,15 +79,18 @@
@Composable
private fun ColorRect() {
var toState by mutableStateOf(OverlayState.Closed)
- handler.postDelayed(object : Runnable {
- override fun run() {
- if ((0..1).random() == 0) {
- toState = OverlayState.Open
- } else {
- toState = OverlayState.Closed
+ handler.postDelayed(
+ object : Runnable {
+ override fun run() {
+ if ((0..1).random() == 0) {
+ toState = OverlayState.Open
+ } else {
+ toState = OverlayState.Closed
+ }
}
- }
- }, (200..800).random().toLong())
+ },
+ (200..800).random().toLong()
+ )
val state = transition(definition = definition, toState = toState)
ColorRectState(state = state)
}
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateBasedRippleDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateBasedRippleDemo.kt
index 3b0531e..5158e54 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateBasedRippleDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateBasedRippleDemo.kt
@@ -61,7 +61,8 @@
}
val state = transition(definition = rippleTransDef, toState = toState.value)
RippleRectFromState(
- Modifier.pressIndicatorGestureFilter(onStart = onPress, onStop = onRelease), state = state)
+ Modifier.pressIndicatorGestureFilter(onStart = onPress, onStop = onRelease), state = state
+ )
}
@Composable
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SwipeToDismissDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SwipeToDismissDemo.kt
index c98ae3a..8d7e2e7 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SwipeToDismissDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SwipeToDismissDemo.kt
@@ -67,59 +67,63 @@
val index = remember { mutableStateOf(0) }
val itemWidth = remember { mutableStateOf(0f) }
val isFlinging = remember { mutableStateOf(false) }
- val modifier = Modifier.rawDragGestureFilter(dragObserver = object : DragObserver {
- override fun onStart(downPosition: Offset) {
- itemBottom.setBounds(0f, height)
- if (isFlinging.value && itemBottom.targetValue < 100f) {
- reset()
+ val modifier = Modifier.rawDragGestureFilter(
+ dragObserver = object : DragObserver {
+ override fun onStart(downPosition: Offset) {
+ itemBottom.setBounds(0f, height)
+ if (isFlinging.value && itemBottom.targetValue < 100f) {
+ reset()
+ }
}
- }
- private fun reset() {
- itemBottom.snapTo(height)
- index.value--
- if (index.value < 0) {
- index.value += pastelColors.size
+ private fun reset() {
+ itemBottom.snapTo(height)
+ index.value--
+ if (index.value < 0) {
+ index.value += pastelColors.size
+ }
}
- }
- override fun onDrag(dragDistance: Offset): Offset {
- itemBottom.snapTo(itemBottom.targetValue + dragDistance.y)
- return dragDistance
- }
+ override fun onDrag(dragDistance: Offset): Offset {
+ itemBottom.snapTo(itemBottom.targetValue + dragDistance.y)
+ return dragDistance
+ }
- fun adjustTarget(velocity: Float): (Float) -> TargetAnimation? {
- return { target: Float ->
- // The velocity is fast enough to fly off screen
- if (target <= 0) {
- null
- } else {
- val animation = SpringSpec<Float>(
- dampingRatio = 0.8f, stiffness = 300f
- )
- val projectedTarget = target + sign(velocity) * 0.2f * height
- if (projectedTarget < 0.6 * height) {
- TargetAnimation(0f, animation)
+ fun adjustTarget(velocity: Float): (Float) -> TargetAnimation? {
+ return { target: Float ->
+ // The velocity is fast enough to fly off screen
+ if (target <= 0) {
+ null
} else {
- TargetAnimation(height, animation)
+ val animation = SpringSpec<Float>(
+ dampingRatio = 0.8f, stiffness = 300f
+ )
+ val projectedTarget = target + sign(velocity) * 0.2f * height
+ if (projectedTarget < 0.6 * height) {
+ TargetAnimation(0f, animation)
+ } else {
+ TargetAnimation(height, animation)
+ }
}
}
}
- }
- override fun onStop(velocity: Offset) {
- isFlinging.value = true
- itemBottom.fling(velocity.y,
- ExponentialDecay(3.0f),
- adjustTarget(velocity.y),
- onEnd = { endReason, final, _ ->
- isFlinging.value = false
- if (endReason != AnimationEndReason.Interrupted && final == 0f) {
- reset()
+ override fun onStop(velocity: Offset) {
+ isFlinging.value = true
+ itemBottom.fling(
+ velocity.y,
+ ExponentialDecay(3.0f),
+ adjustTarget(velocity.y),
+ onEnd = { endReason, final, _ ->
+ isFlinging.value = false
+ if (endReason != AnimationEndReason.Interrupted && final == 0f) {
+ reset()
+ }
}
- })
+ )
+ }
}
- })
+ )
val heightDp = with(DensityAmbient.current) { height.toDp() }
diff --git a/compose/animation/animation/samples/build.gradle b/compose/animation/animation/samples/build.gradle
index d9238e5..ba7416f 100644
--- a/compose/animation/animation/samples/build.gradle
+++ b/compose/animation/animation/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedValueSamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedValueSamples.kt
index 208d1fc..20862c0 100644
--- a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedValueSamples.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedValueSamples.kt
@@ -70,10 +70,13 @@
MySize(100.dp, 100.dp)
}
}
- val animSize = animate<MySize, AnimationVector2D>(mySize, TwoWayConverter(
- convertToVector = { AnimationVector2D(it.width.value, it.height.value) },
- convertFromVector = { MySize(it.v1.dp, it.v2.dp) }
- ))
+ val animSize = animate<MySize, AnimationVector2D>(
+ mySize,
+ TwoWayConverter(
+ convertToVector = { AnimationVector2D(it.width.value, it.height.value) },
+ convertFromVector = { MySize(it.v1.dp, it.v2.dp) }
+ )
+ )
Box(Modifier.preferredSize(animSize.width, animSize.height).background(color = Color.Red))
}
}
diff --git a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt
index a4027e7..46c7c31 100644
--- a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt
@@ -145,7 +145,8 @@
@Composable
fun FullyLoadedTransition() {
var visible by remember { mutableStateOf(true) }
- AnimatedVisibility(visible = visible,
+ AnimatedVisibility(
+ visible = visible,
enter = slideInVertically(
// Start the slide from 40 (pixels) above where the content is supposed to go, to
// produce a parallax effect
@@ -153,7 +154,8 @@
) + expandVertically(
expandFrom = Alignment.Top
) + fadeIn(initialAlpha = 0.3f),
- exit = slideOutVertically() + shrinkVertically() + fadeOut()) {
+ exit = slideOutVertically() + shrinkVertically() + fadeOut()
+ ) {
// Content that needs to appear/disappear goes here:
Text("Content to appear/disappear", Modifier.fillMaxWidth().height(200.dp))
}
@@ -214,7 +216,8 @@
fun ExpandShrinkVerticallySample() {
var visible by remember { mutableStateOf(true) }
- AnimatedVisibility(visible,
+ AnimatedVisibility(
+ visible,
// Sets the initial height of the content to 20, revealing only the top of the content at
// the beginning of the expanding animation.
enter = expandVertically(
@@ -270,9 +273,11 @@
fun ColumnAnimatedVisibilitySample() {
var itemIndex by remember { mutableStateOf(0) }
val colors = listOf(Color.Red, Color.Green, Color.Blue)
- Column(Modifier.fillMaxWidth().clickable {
- itemIndex = (itemIndex + 1) % colors.size
- }) {
+ Column(
+ Modifier.fillMaxWidth().clickable {
+ itemIndex = (itemIndex + 1) % colors.size
+ }
+ ) {
colors.forEachIndexed { i, color ->
// By default ColumnScope.AnimatedVisibility expands and shrinks new content while
// fading.
diff --git a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt
index 17c1672..87b80fc 100644
--- a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt
@@ -41,14 +41,16 @@
val shortText = "Hi"
val longText = "Very long text\nthat spans across\nmultiple lines"
var short by remember { mutableStateOf(true) }
- Box(modifier = Modifier
- .background(Color.Blue,
- RoundedCornerShape(15.dp)
- )
- .clickable { short = !short }
- .padding(20.dp)
- .wrapContentSize()
- .animateContentSize()
+ Box(
+ modifier = Modifier
+ .background(
+ Color.Blue,
+ RoundedCornerShape(15.dp)
+ )
+ .clickable { short = !short }
+ .padding(20.dp)
+ .wrapContentSize()
+ .animateContentSize()
) {
Text(
if (short) {
diff --git a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt
index 0dc02f8..e30277a 100644
--- a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt
@@ -70,7 +70,8 @@
// This starts the transition going from State.First to State.Second when this composable
// gets composed for the first time.
val state = transition(
- definition = definition, initState = State.First, toState = State.Second)
+ definition = definition, initState = State.First, toState = State.Second
+ )
Box(
Modifier
.preferredSize(state[widthKey], state[heightKey])
diff --git a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
index 410a039..97906e1 100644
--- a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
+++ b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
@@ -74,9 +74,11 @@
tween(100, easing = FastOutSlowInEasing)
)
) {
- Stack(Modifier.onPositioned {
- offset = it.localToRoot(Offset.Zero)
- }.size(100.dp, 100.dp)) {
+ Stack(
+ Modifier.onPositioned {
+ offset = it.localToRoot(Offset.Zero)
+ }.size(100.dp, 100.dp)
+ ) {
onDispose {
disposed = true
}
@@ -176,9 +178,11 @@
tween(100, easing = FastOutSlowInEasing)
)
) {
- Stack(Modifier.onPositioned {
- offset = it.localToRoot(Offset.Zero)
- }.size(100.dp, 100.dp)) {
+ Stack(
+ Modifier.onPositioned {
+ offset = it.localToRoot(Offset.Zero)
+ }.size(100.dp, 100.dp)
+ ) {
onDispose {
disposed = true
}
diff --git a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/SingleValueAnimationTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/SingleValueAnimationTest.kt
index 2eba353..b41f4d5 100644
--- a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/SingleValueAnimationTest.kt
+++ b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/SingleValueAnimationTest.kt
@@ -293,7 +293,8 @@
var value = Color.Black
val children: @Composable() (Boolean) -> Unit = { enabled ->
value = animate(
- if (enabled) Color.Cyan else Color.Black, TweenSpec(
+ if (enabled) Color.Cyan else Color.Black,
+ TweenSpec(
durationMillis = 100,
easing = FastOutLinearInEasing
)
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
index e5ec767..932202d 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
@@ -118,7 +118,8 @@
} ?: AnimData(
AnimatedValueModel(
targetSize, IntSize.VectorConverter, clock, IntSize(1, 1)
- ), targetSize
+ ),
+ targetSize
)
animData = data
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt
index 21df8cf..38adbe5 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt
@@ -116,7 +116,8 @@
if (reason == AnimationEndReason.TargetReached) {
onAnimationFinish()
}
- })
+ }
+ )
}
return animatedFloat
}
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
index 262d6fe..73c11e1 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
@@ -969,7 +969,8 @@
IntSize.VectorConverter,
clock,
visibilityThreshold = IntSize(1, 1)
- ), enter.alignment, enter.clip, listener
+ ),
+ enter.alignment, enter.clip, listener
)
// Animate to full size
sizeAnim = anim.animateTo(
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt
index 0360f16..1e6e430 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt
@@ -59,11 +59,14 @@
*
* @see [TransitionDefinition]
*/
-@Deprecated("Transition has been renamed to transition, which returns a TransitionState instead " +
+@Deprecated(
+ "Transition has been renamed to transition, which returns a TransitionState instead " +
"of passing it to children",
replaceWith = ReplaceWith(
"transition(definition, toState, clock, initState, null, onStateChangeFinished)",
- "androidx.compose.animation.transition"))
+ "androidx.compose.animation.transition"
+ )
+)
@Composable
fun <T> Transition(
definition: TransitionDefinition<T>,
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys.kt
index ea49d3f..e9a2745 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys.kt
@@ -210,8 +210,8 @@
* [ColorSpace].
*/
val Color.Companion.VectorConverter:
- (colorSpace: ColorSpace) -> TwoWayConverter<Color, AnimationVector4D>
- get() = ColorToVector
+ (colorSpace: ColorSpace) -> TwoWayConverter<Color, AnimationVector4D>
+ get() = ColorToVector
/**
* A lambda that takes a [ColorSpace] and returns a converter that can both convert a [Color] to
@@ -308,8 +308,10 @@
* A type converter that converts a [PxBounds] to a [AnimationVector4D], and vice versa.
* @see Rect.Companion.VectorConverter
*/
-@Deprecated("Use Rect and RectToVectorConverter instead",
- ReplaceWith("Rect.VectorConverter"))
+@Deprecated(
+ "Use Rect and RectToVectorConverter instead",
+ ReplaceWith("Rect.VectorConverter")
+)
@Suppress("DEPRECATION")
val PxBounds.Companion.VectorConverter: TwoWayConverter<PxBounds, AnimationVector4D>
get() = PxBoundsToVector
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt
index f0aaef8..bb63f17 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt
@@ -241,7 +241,7 @@
animSpec: AnimationSpec<Bounds> = remember {
SpringSpec(
visibilityThreshold = Bounds.VectorConverter.convertFromVector
- (DpVisibilityThreshold4D)
+ (DpVisibilityThreshold4D)
)
},
endListener: ((Bounds) -> Unit)? = null
@@ -304,7 +304,7 @@
animSpec: AnimationSpec<Rect> = remember {
SpringSpec(
visibilityThreshold =
- Rect.VectorConverter.convertFromVector(PxVisibilityThreshold4D)
+ Rect.VectorConverter.convertFromVector(PxVisibilityThreshold4D)
)
},
endListener: ((Rect) -> Unit)? = null
@@ -330,10 +330,15 @@
* animation will be used by default.
* @param endListener An optional end listener to get notified when the animation is finished.
*/
-@Deprecated("Consider usage of Rect instead",
- ReplaceWith("animate(target: Rect, animSpec: AnimationSpec<Rect>, " +
+@Deprecated(
+ "Consider usage of Rect instead",
+ ReplaceWith(
+ "animate(target: Rect, animSpec: AnimationSpec<Rect>, " +
"endListener: ((Rect) -> " +
- "Unit)?", "androidx.compose.animation.animation"))
+ "Unit)?",
+ "androidx.compose.animation.animation"
+ )
+)
@Suppress("DEPRECATION")
@Composable
fun animate(
@@ -341,7 +346,7 @@
animSpec: AnimationSpec<PxBounds> = remember {
SpringSpec(
visibilityThreshold =
- PxBounds.VectorConverter.convertFromVector(PxVisibilityThreshold4D)
+ PxBounds.VectorConverter.convertFromVector(PxVisibilityThreshold4D)
)
},
endListener: ((PxBounds) -> Unit)? = null
diff --git a/compose/animation/animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt b/compose/animation/animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt
index 7bdf8c34..cbe47ba 100644
--- a/compose/animation/animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt
+++ b/compose/animation/animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt
@@ -38,19 +38,24 @@
val converter = (Color.VectorConverter)(ColorSpaces.Srgb)
assertEquals(converter.convertFromVector(AnimationVector4D(1f, 1f, 0f, 0f)), Color.Red)
assertEquals(converter.convertToVector(Color.Green), AnimationVector4D(1f, 0f, 1f, 0f))
- assertEquals(converter.convertFromVector(AnimationVector4D(0f, 0f, 0f, 1f)),
- Color(alpha = 0f, red = 0f, green = 0f, blue = 1f))
+ assertEquals(
+ converter.convertFromVector(AnimationVector4D(0f, 0f, 0f, 1f)),
+ Color(alpha = 0f, red = 0f, green = 0f, blue = 1f)
+ )
}
@Test
fun testRectConverter() {
assertEquals(
Rect.VectorConverter.convertToVector(Rect(1f, 2f, 3f, 4f)),
- AnimationVector4D(1f, 2f, 3f, 4f))
+ AnimationVector4D(1f, 2f, 3f, 4f)
+ )
assertEquals(
Rect.VectorConverter.convertFromVector(
- AnimationVector4D(-400f, -300f, -200f, -100f)),
- Rect(-400f, -300f, -200f, -100f))
+ AnimationVector4D(-400f, -300f, -200f, -100f)
+ ),
+ Rect(-400f, -300f, -200f, -100f)
+ )
}
@Test
@@ -66,9 +71,13 @@
fun testOffsetConverter() {
val x = Random.nextFloat()
val y = Random.nextFloat()
- assertEquals(Offset(x, y),
- Offset.VectorConverter.convertFromVector(AnimationVector2D(x, y)))
- assertEquals(AnimationVector2D(x, y),
- Offset.VectorConverter.convertToVector(Offset(x, y)))
+ assertEquals(
+ Offset(x, y),
+ Offset.VectorConverter.convertFromVector(AnimationVector2D(x, y))
+ )
+ assertEquals(
+ AnimationVector2D(x, y),
+ Offset.VectorConverter.convertToVector(Offset(x, y))
+ )
}
}
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/build.gradle b/compose/compiler/compiler-hosted/build.gradle
similarity index 96%
rename from compose/compose-compiler-hosted/build.gradle
rename to compose/compiler/compiler-hosted/build.gradle
index dd10fd1..63b0577 100644
--- a/compose/compose-compiler-hosted/build.gradle
+++ b/compose/compiler/compiler-hosted/build.gradle
@@ -46,7 +46,7 @@
publish = Publish.SNAPSHOT_AND_RELEASE
toolingProject = true
mavenVersion = LibraryVersions.COMPOSE
- mavenGroup = LibraryGroups.COMPOSE
+ mavenGroup = LibraryGroups.Compose.COMPILER
inceptionYear = "2019"
description = "Contains the Kotlin compiler plugin for Compose used in Android Studio and IDEA"
compilationTarget = CompilationTarget.HOST
diff --git a/compose/compose-compiler-hosted/integration-tests/build.gradle b/compose/compiler/compiler-hosted/integration-tests/build.gradle
similarity index 95%
rename from compose/compose-compiler-hosted/integration-tests/build.gradle
rename to compose/compiler/compiler-hosted/integration-tests/build.gradle
index 326ec15..c8f3d09 100644
--- a/compose/compose-compiler-hosted/integration-tests/build.gradle
+++ b/compose/compiler/compiler-hosted/integration-tests/build.gradle
@@ -37,7 +37,7 @@
testImplementation(KOTLIN_STDLIB)
testImplementation(project(":compose:androidview:androidview"))
- testImplementation(project(":compose:compose-compiler-hosted"))
+ testImplementation(project(":compose:compiler:compiler-hosted"))
testImplementation(project(":compose:runtime:runtime"))
testImplementation(project(":compose:ui:ui"))
testImplementation("androidx.core:core-ktx:1.1.0")
@@ -74,7 +74,6 @@
name = "AndroidX Compiler CLI Tests"
publish = Publish.NONE
toolingProject = true
- mavenGroup = LibraryGroups.COMPOSE
inceptionYear = "2019"
description = "Contains test for the compose compiler plugin"
}
diff --git a/compose/compose-compiler-hosted/integration-tests/src/main/AndroidManifest.xml b/compose/compiler/compiler-hosted/integration-tests/src/main/AndroidManifest.xml
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/main/AndroidManifest.xml
rename to compose/compiler/compiler-hosted/integration-tests/src/main/AndroidManifest.xml
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenSignatureTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenSignatureTest.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenSignatureTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenSignatureTest.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenTest.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenTest.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
similarity index 98%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
index e8837758..2b7c8f5 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
@@ -221,7 +221,7 @@
companion object {
val homeDir by lazy { File(computeHomeDirectory()).absolutePath }
- val projectRoot by lazy { File(homeDir, "../../../../..").absolutePath }
+ val projectRoot by lazy { File(homeDir, "../../../../../..").absolutePath }
val kotlinHome by lazy {
File(projectRoot, "prebuilts/androidx/external/org/jetbrains/kotlin/")
}
@@ -229,8 +229,7 @@
File(System.getenv("OUT_DIR") ?: File(projectRoot, "out").absolutePath)
}
val composePluginJar by lazy {
-
- File(outDir, "ui/compose/compose-compiler/build/jarjar/compose-compiler.jar")
+ File(outDir, "ui/compose/compiler/compiler/build/jarjar/compiler.jar")
}
fun kotlinRuntimeJar(module: String) = File(
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractComposeDiagnosticsTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractComposeDiagnosticsTest.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractComposeDiagnosticsTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractComposeDiagnosticsTest.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractControlFlowTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractControlFlowTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractControlFlowTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractControlFlowTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractIrTransformTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractIrTransformTest.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractIrTransformTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractIrTransformTest.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractLoweringTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractLoweringTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractLoweringTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractLoweringTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractMultiPlatformIntegrationTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractMultiPlatformIntegrationTest.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractMultiPlatformIntegrationTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractMultiPlatformIntegrationTest.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/CodegenTestFiles.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/CodegenTestFiles.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/CodegenTestFiles.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/CodegenTestFiles.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallLoweringTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallLoweringTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallLoweringTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallLoweringTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallResolverTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallResolverTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallResolverTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallResolverTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCodegenTestUtils.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCodegenTestUtils.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCodegenTestUtils.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCodegenTestUtils.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeMultiPlatformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeMultiPlatformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeMultiPlatformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeMultiPlatformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeRobolectricTestRunner.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeRobolectricTestRunner.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeRobolectricTestRunner.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeRobolectricTestRunner.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamSignatureTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamSignatureTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamSignatureTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamSignatureTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTestsNoSource.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTestsNoSource.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTestsNoSource.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTestsNoSource.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DefaultParamTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DefaultParamTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DefaultParamTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DefaultParamTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DurableKeyTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DurableKeyTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DurableKeyTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DurableKeyTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FcsTypeResolutionTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FcsTypeResolutionTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FcsTypeResolutionTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FcsTypeResolutionTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/GenerationUtils.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/GenerationUtils.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/GenerationUtils.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/GenerationUtils.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/JvmResolveUtil.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/JvmResolveUtil.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/JvmResolveUtil.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/JvmResolveUtil.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxCrossModuleTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxCrossModuleTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxCrossModuleTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxCrossModuleTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxTransformationTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxTransformationTest.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxTransformationTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxTransformationTest.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralCodegenTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralCodegenTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralCodegenTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralCodegenTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RememberIntrinsicTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RememberIntrinsicTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RememberIntrinsicTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RememberIntrinsicTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RobolectricComposeTester.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RobolectricComposeTester.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RobolectricComposeTester.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RobolectricComposeTester.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ScopeComposabilityTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ScopeComposabilityTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ScopeComposabilityTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ScopeComposabilityTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TestsCompilerError.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TestsCompilerError.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TestsCompilerError.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TestsCompilerError.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableCheckerTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableCheckerTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableCheckerTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableCheckerTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableDeclarationCheckerTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableDeclarationCheckerTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableDeclarationCheckerTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableDeclarationCheckerTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/TryCatchComposableCheckerTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/TryCatchComposableCheckerTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/TryCatchComposableCheckerTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/TryCatchComposableCheckerTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/UnionCheckerTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/UnionCheckerTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/UnionCheckerTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/UnionCheckerTests.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableCallChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableCallChecker.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableCallChecker.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableCallChecker.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeDiagnosticSuppressor.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeDiagnosticSuppressor.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeDiagnosticSuppressor.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeDiagnosticSuppressor.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrorMessages.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrorMessages.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrorMessages.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrorMessages.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrors.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrors.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrors.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrors.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFlags.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFlags.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFlags.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFlags.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFqNames.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFqNames.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFqNames.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFqNames.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeTypeResolutionInterceptorExtension.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeTypeResolutionInterceptorExtension.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeTypeResolutionInterceptorExtension.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeTypeResolutionInterceptorExtension.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/KtxNameConventions.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/KtxNameConventions.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/KtxNameConventions.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/KtxNameConventions.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/TryCatchComposableChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/TryCatchComposableChecker.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/TryCatchComposableChecker.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/TryCatchComposableChecker.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/UnionAnnotationChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/UnionAnnotationChecker.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/UnionAnnotationChecker.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/UnionAnnotationChecker.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ValidatedAssignment.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ValidatedAssignment.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ValidatedAssignment.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ValidatedAssignment.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/WeakBindingTrace.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/WeakBindingTrace.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/WeakBindingTrace.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/WeakBindingTrace.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposeWritableSlices.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposeWritableSlices.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposeWritableSlices.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposeWritableSlices.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/DurableKeyVisitor.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/DurableKeyVisitor.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/DurableKeyVisitor.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/DurableKeyVisitor.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/FakeJvmSymbols.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/FakeJvmSymbols.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/FakeJvmSymbols.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/FakeJvmSymbols.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ModuleLoweringPass.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ModuleLoweringPass.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ModuleLoweringPass.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ModuleLoweringPass.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/package-info.java b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/package-info.java
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/package-info.java
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/package-info.java
diff --git a/compose/compose-compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor b/compose/compiler/compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
rename to compose/compiler/compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
diff --git a/compose/compose-compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar b/compose/compiler/compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
rename to compose/compiler/compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
diff --git a/compose/compose-compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages$Extension b/compose/compiler/compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages$Extension
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages$Extension
rename to compose/compiler/compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages$Extension
diff --git a/compose/compose-compiler/build.gradle b/compose/compiler/compiler/build.gradle
similarity index 92%
rename from compose/compose-compiler/build.gradle
rename to compose/compiler/compiler/build.gradle
index 2d52b62..5adff18 100644
--- a/compose/compose-compiler/build.gradle
+++ b/compose/compiler/compiler/build.gradle
@@ -34,11 +34,11 @@
apply plugin: 'org.anarres.jarjar'
dependencies {
- compileOnly(project(":compose:compose-compiler-hosted"))
+ compileOnly(project(":compose:compiler:compiler-hosted"))
}
jarjar.repackage('embeddedPlugin') {
- destinationName "compose-compiler.jar"
+ destinationName "compiler.jar"
from configurations.compileClasspath
classRename 'com.intellij.**', 'org.jetbrains.kotlin.com.intellij.@1'
}
@@ -60,7 +60,7 @@
publish = Publish.SNAPSHOT_AND_RELEASE
toolingProject = true
mavenVersion = LibraryVersions.COMPOSE
- mavenGroup = LibraryGroups.COMPOSE
+ mavenGroup = LibraryGroups.Compose.COMPILER
inceptionYear = "2019"
description = "Compiler plugin that enables Compose"
compilationTarget = CompilationTarget.HOST
diff --git a/compose/desktop/desktop/build.gradle b/compose/desktop/desktop/build.gradle
index dfb6564..7c93116 100644
--- a/compose/desktop/desktop/build.gradle
+++ b/compose/desktop/desktop/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/compose/desktop/desktop/samples/build.gradle b/compose/desktop/desktop/samples/build.gradle
index c8c5629..74ba22e 100644
--- a/compose/desktop/desktop/samples/build.gradle
+++ b/compose/desktop/desktop/samples/build.gradle
@@ -27,7 +27,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.kt
index a34fb25..797a79b 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.kt
@@ -122,10 +122,12 @@
if (animation.value) {
appendInlineContent(inlineIndicatorId)
}
- pushStyle(SpanStyle(
- color = Color(0xff964B00),
- shadow = Shadow(Color.Green, offset = Offset(1f, 1f))
- ))
+ pushStyle(
+ SpanStyle(
+ color = Color(0xff964B00),
+ shadow = Shadow(Color.Green, offset = Offset(1f, 1f))
+ )
+ )
append("brown fox")
pop()
pushStyle(SpanStyle(background = Color.Yellow))
@@ -165,13 +167,13 @@
TextDecoration.LineThrough
)
val lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do" +
- " eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" +
- " minim veniam, quis nostrud exercitation ullamco laboris nisi ut" +
- " aliquipex ea commodo consequat. Duis aute irure dolor in reprehenderit" +
- " in voluptate velit esse cillum dolore eu fugiat nulla pariatur." +
- " Excepteur" +
- " sint occaecat cupidatat non proident, sunt in culpa qui officia" +
- " deserunt mollit anim id est laborum."
+ " eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" +
+ " minim veniam, quis nostrud exercitation ullamco laboris nisi ut" +
+ " aliquipex ea commodo consequat. Duis aute irure dolor in reprehenderit" +
+ " in voluptate velit esse cillum dolore eu fugiat nulla pariatur." +
+ " Excepteur" +
+ " sint occaecat cupidatat non proident, sunt in culpa qui officia" +
+ " deserunt mollit anim id est laborum."
var loremDecoration by remember { mutableStateOf(0) }
Text(
text = lorem,
@@ -200,13 +202,13 @@
Text(
text = "fun <T : Comparable<T>> List<T>.quickSort(): List<T> = when {\n" +
- " size < 2 -> this\n" +
- " else -> {\n" +
- " val pivot = first()\n" +
- " val (smaller, greater) = drop(1).partition { it <= pivot }\n" +
- " smaller.quickSort() + pivot + greater.quickSort()\n" +
- " }\n" +
- "}",
+ " size < 2 -> this\n" +
+ " else -> {\n" +
+ " val pivot = first()\n" +
+ " val (smaller, greater) = drop(1).partition { it <= pivot }\n" +
+ " smaller.quickSort() + pivot + greater.quickSort()\n" +
+ " }\n" +
+ "}",
modifier = Modifier.padding(10.dp).pointerMoveFilter(
onMove = { position ->
println("MOVE: $position")
@@ -221,12 +223,16 @@
println("UNHOVER!")
text.value = "UNHOVER ${amount.value}"
false
- })
+ }
+ )
)
- Button(modifier = Modifier.padding(4.dp), onClick = {
- amount.value++
- }) {
+ Button(
+ modifier = Modifier.padding(4.dp),
+ onClick = {
+ amount.value++
+ }
+ ) {
Text("Base")
}
@@ -239,7 +245,8 @@
modifier = Modifier.padding(4.dp),
onClick = {
animation.value = !animation.value
- }) {
+ }
+ ) {
Text("Toggle")
}
@@ -249,7 +256,8 @@
Window(size = IntSize(400, 200)) {
Animations(isCircularEnabled = animation.value)
}
- }) {
+ }
+ ) {
Text("Window")
}
}
@@ -257,8 +265,10 @@
Animations(isCircularEnabled = animation.value)
}
- Slider(value = amount.value.toFloat() / 100f,
- onValueChange = { amount.value = (it * 100).toInt() })
+ Slider(
+ value = amount.value.toFloat() / 100f,
+ onValueChange = { amount.value = (it * 100).toInt() }
+ )
TextField(
value = amount.value.toString(),
onValueChange = { amount.value = it.toIntOrNull() ?: 42 },
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppContent.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppContent.kt
index e887578..42db6ac 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppContent.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppContent.kt
@@ -73,9 +73,12 @@
println("Second window is dismissed.")
}
).show {
- WindowContent(amount, onClose = {
- AppManager.getCurrentFocusedWindow()?.close()
- })
+ WindowContent(
+ amount,
+ onClose = {
+ AppManager.getCurrentFocusedWindow()?.close()
+ }
+ )
}
}
)
diff --git a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/desktop/ParagraphTest.kt b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/desktop/ParagraphTest.kt
index 7277c2f..347723a 100644
--- a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/desktop/ParagraphTest.kt
+++ b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/desktop/ParagraphTest.kt
@@ -51,22 +51,22 @@
private val text1 =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do" +
- " eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" +
- " minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip" +
- " ex ea commodo consequat. Duis aute irure dolor in reprehenderit in" +
- " voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur" +
- " sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt" +
- " mollit anim id est laborum."
+ " eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" +
+ " minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip" +
+ " ex ea commodo consequat. Duis aute irure dolor in reprehenderit in" +
+ " voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur" +
+ " sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt" +
+ " mollit anim id est laborum."
private val text2 =
"fun <T : Comparable<T>> List<T>.quickSort(): List<T> = when {\n" +
- " size < 2 -> this\n" +
- " else -> {\n" +
- " val pivot = first()\n" +
- " val (smaller, greater) = drop(1).partition { it <= pivot }\n" +
- " smaller.quickSort() + pivot + greater.quickSort()\n" +
- " }\n" +
- "}"
+ " size < 2 -> this\n" +
+ " else -> {\n" +
+ " val pivot = first()\n" +
+ " val (smaller, greater) = drop(1).partition { it <= pivot }\n" +
+ " smaller.quickSort() + pivot + greater.quickSort()\n" +
+ " }\n" +
+ "}"
val fontFamily = fontFamily(
font("Noto", "NotoSans-Regular.ttf"),
diff --git a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPaintTest.kt b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPaintTest.kt
index fff340a..5154080 100644
--- a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPaintTest.kt
+++ b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPaintTest.kt
@@ -46,10 +46,13 @@
@Test
fun blendModePlus() {
canvas.drawRect(left = 0f, top = 0f, right = 16f, bottom = 16f, paint = redPaint)
- canvas.drawRect(left = 4f, top = 4f, right = 12f, bottom = 12f, paint = Paint().apply {
- color = Color.Blue
- blendMode = BlendMode.Plus
- })
+ canvas.drawRect(
+ left = 4f, top = 4f, right = 12f, bottom = 12f,
+ paint = Paint().apply {
+ color = Color.Blue
+ blendMode = BlendMode.Plus
+ }
+ )
screenshotRule.snap(surface)
}
@@ -57,10 +60,13 @@
@Test
fun blendModeMultiply() {
canvas.drawRect(left = 0f, top = 0f, right = 16f, bottom = 16f, paint = redPaint)
- canvas.drawRect(left = 4f, top = 4f, right = 12f, bottom = 12f, paint = Paint().apply {
- color = Color.Gray
- blendMode = BlendMode.Multiply
- })
+ canvas.drawRect(
+ left = 4f, top = 4f, right = 12f, bottom = 12f,
+ paint = Paint().apply {
+ color = Color.Gray
+ blendMode = BlendMode.Multiply
+ }
+ )
screenshotRule.snap(surface)
}
@@ -118,14 +124,17 @@
fun linearGradientShader() {
canvas.drawRect(left = 0f, top = 0f, right = 16f, bottom = 16f, paint = redPaint)
- canvas.drawRect(left = 2f, top = 2f, right = 14f, bottom = 14f, paint = Paint().apply {
- shader = LinearGradientShader(
- from = Offset(0f, 0f),
- to = Offset(6f, 6f),
- colors = listOf(Color.Blue, Color.Green),
- tileMode = TileMode.Mirror
- )
- })
+ canvas.drawRect(
+ left = 2f, top = 2f, right = 14f, bottom = 14f,
+ paint = Paint().apply {
+ shader = LinearGradientShader(
+ from = Offset(0f, 0f),
+ to = Offset(6f, 6f),
+ colors = listOf(Color.Blue, Color.Green),
+ tileMode = TileMode.Mirror
+ )
+ }
+ )
screenshotRule.snap(surface)
}
@@ -134,15 +143,18 @@
fun linearGradientShaderWithStops() {
canvas.drawRect(left = 0f, top = 0f, right = 16f, bottom = 16f, paint = redPaint)
- canvas.drawRect(left = 1f, top = 2f, right = 14f, bottom = 15f, paint = Paint().apply {
- shader = LinearGradientShader(
- from = Offset(0f, 0f),
- to = Offset(12f, 0f),
- colorStops = listOf(0f, 0.25f, 1f),
- colors = listOf(Color.Blue, Color.Green, Color.Yellow),
- tileMode = TileMode.Mirror
- )
- })
+ canvas.drawRect(
+ left = 1f, top = 2f, right = 14f, bottom = 15f,
+ paint = Paint().apply {
+ shader = LinearGradientShader(
+ from = Offset(0f, 0f),
+ to = Offset(12f, 0f),
+ colorStops = listOf(0f, 0.25f, 1f),
+ colors = listOf(Color.Blue, Color.Green, Color.Yellow),
+ tileMode = TileMode.Mirror
+ )
+ }
+ )
screenshotRule.snap(surface)
}
@@ -151,14 +163,17 @@
fun radialGradientShader() {
canvas.drawRect(left = 0f, top = 0f, right = 16f, bottom = 16f, paint = redPaint)
- canvas.drawRect(left = 2f, top = 2f, right = 14f, bottom = 14f, paint = Paint().apply {
- shader = RadialGradientShader(
- center = Offset(4f, 8f),
- radius = 8f,
- colors = listOf(Color.Blue, Color.Green),
- tileMode = TileMode.Clamp
- )
- })
+ canvas.drawRect(
+ left = 2f, top = 2f, right = 14f, bottom = 14f,
+ paint = Paint().apply {
+ shader = RadialGradientShader(
+ center = Offset(4f, 8f),
+ radius = 8f,
+ colors = listOf(Color.Blue, Color.Green),
+ tileMode = TileMode.Clamp
+ )
+ }
+ )
screenshotRule.snap(surface)
}
diff --git a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPathTest.kt b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPathTest.kt
index 9ce4554..85a721a 100644
--- a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPathTest.kt
+++ b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPathTest.kt
@@ -149,10 +149,13 @@
relativeLineTo(0f, -8f)
}
- canvas.drawPath(path, redPaint.apply {
- style = PaintingStyle.Stroke
- strokeWidth = 2f
- })
+ canvas.drawPath(
+ path,
+ redPaint.apply {
+ style = PaintingStyle.Stroke
+ strokeWidth = 2f
+ }
+ )
screenshotRule.snap(surface)
}
diff --git a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/canvas/DesktopCanvasTest.kt b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/canvas/DesktopCanvasTest.kt
index 789ee32..f196391 100644
--- a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/canvas/DesktopCanvasTest.kt
+++ b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/canvas/DesktopCanvasTest.kt
@@ -121,49 +121,70 @@
@Test
fun drawLine() {
- canvas.drawLine(Offset(-4f, -4f), Offset(4f, 4f), Paint().apply {
- color = Color.Red
- strokeWidth = 1f
- strokeCap = StrokeCap.Butt
- })
- canvas.drawLine(Offset(8f, 4f), Offset(8f, 12f), Paint().apply {
- color = Color.Blue
- strokeWidth = 4f
- strokeCap = StrokeCap.Butt
- })
- canvas.drawLine(Offset(12f, 4f), Offset(12f, 12f), Paint().apply {
- color = Color.Green
- strokeWidth = 4f
- strokeCap = StrokeCap.Round
- })
- canvas.drawLine(Offset(4f, 4f), Offset(4f, 12f), Paint().apply {
- color = Color.Black.copy(alpha = 0.5f)
- strokeWidth = 4f
- strokeCap = StrokeCap.Square
- })
+ canvas.drawLine(
+ Offset(-4f, -4f), Offset(4f, 4f),
+ Paint().apply {
+ color = Color.Red
+ strokeWidth = 1f
+ strokeCap = StrokeCap.Butt
+ }
+ )
+ canvas.drawLine(
+ Offset(8f, 4f), Offset(8f, 12f),
+ Paint().apply {
+ color = Color.Blue
+ strokeWidth = 4f
+ strokeCap = StrokeCap.Butt
+ }
+ )
+ canvas.drawLine(
+ Offset(12f, 4f), Offset(12f, 12f),
+ Paint().apply {
+ color = Color.Green
+ strokeWidth = 4f
+ strokeCap = StrokeCap.Round
+ }
+ )
+ canvas.drawLine(
+ Offset(4f, 4f), Offset(4f, 12f),
+ Paint().apply {
+ color = Color.Black.copy(alpha = 0.5f)
+ strokeWidth = 4f
+ strokeCap = StrokeCap.Square
+ }
+ )
// should draw antialiased two-pixel line
- canvas.drawLine(Offset(4f, 4f), Offset(4f, 12f), Paint().apply {
- color = Color.Yellow
- strokeWidth = 1f
- strokeCap = StrokeCap.Butt
- })
+ canvas.drawLine(
+ Offset(4f, 4f), Offset(4f, 12f),
+ Paint().apply {
+ color = Color.Yellow
+ strokeWidth = 1f
+ strokeCap = StrokeCap.Butt
+ }
+ )
// should draw aliased one-pixel line
- canvas.drawLine(Offset(4f, 4f), Offset(4f, 12f), Paint().apply {
- color = Color.Yellow
- strokeWidth = 1f
- strokeCap = StrokeCap.Butt
- isAntiAlias = false
- })
+ canvas.drawLine(
+ Offset(4f, 4f), Offset(4f, 12f),
+ Paint().apply {
+ color = Color.Yellow
+ strokeWidth = 1f
+ strokeCap = StrokeCap.Butt
+ isAntiAlias = false
+ }
+ )
// shouldn't draw any line
- canvas.drawLine(Offset(4f, 4f), Offset(4f, 12f), Paint().apply {
- color = Color.Yellow
- strokeWidth = 0f
- strokeCap = StrokeCap.Butt
- isAntiAlias = false
- })
+ canvas.drawLine(
+ Offset(4f, 4f), Offset(4f, 12f),
+ Paint().apply {
+ color = Color.Yellow
+ strokeWidth = 0f
+ strokeCap = StrokeCap.Butt
+ isAntiAlias = false
+ }
+ )
screenshotRule.snap(surface)
}
@@ -204,7 +225,8 @@
canvas.drawRect(0f, 0f, 16f, 16f, redPaint)
canvas.withSaveLayer(
- Rect(left = 4f, top = 8f, right = 12f, bottom = 16f), redPaint.apply {
+ Rect(left = 4f, top = 8f, right = 12f, bottom = 16f),
+ redPaint.apply {
blendMode = BlendMode.Plus
}
) {
diff --git a/compose/foundation/foundation-layout/api/current.txt b/compose/foundation/foundation-layout/api/current.txt
index aacbcc9..6740f1d 100644
--- a/compose/foundation/foundation-layout/api/current.txt
+++ b/compose/foundation/foundation-layout/api/current.txt
@@ -51,8 +51,7 @@
}
@androidx.compose.foundation.layout.InternalLayoutApi public static interface Arrangement.Horizontal {
- method public void arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.unit.Density density, java.util.List<java.lang.Integer> outPosition);
- method @Deprecated public default java.util.List<java.lang.Integer> arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.LayoutDirection layoutDirection);
+ method public void arrange(int totalSize, int[] size, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.unit.Density density, int[] outPosition);
method public default float getSpacing();
property public default float spacing;
}
@@ -62,8 +61,7 @@
}
@androidx.compose.foundation.layout.InternalLayoutApi public static interface Arrangement.Vertical {
- method public void arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.Density density, java.util.List<java.lang.Integer> outPosition);
- method @Deprecated public default java.util.List<java.lang.Integer> arrange(int totalSize, java.util.List<java.lang.Integer> size);
+ method public void arrange(int totalSize, int[] size, androidx.compose.ui.unit.Density density, int[] outPosition);
method public default float getSpacing();
property public default float spacing;
}
diff --git a/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt b/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt
index aacbcc9..6740f1d 100644
--- a/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt
@@ -51,8 +51,7 @@
}
@androidx.compose.foundation.layout.InternalLayoutApi public static interface Arrangement.Horizontal {
- method public void arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.unit.Density density, java.util.List<java.lang.Integer> outPosition);
- method @Deprecated public default java.util.List<java.lang.Integer> arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.LayoutDirection layoutDirection);
+ method public void arrange(int totalSize, int[] size, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.unit.Density density, int[] outPosition);
method public default float getSpacing();
property public default float spacing;
}
@@ -62,8 +61,7 @@
}
@androidx.compose.foundation.layout.InternalLayoutApi public static interface Arrangement.Vertical {
- method public void arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.Density density, java.util.List<java.lang.Integer> outPosition);
- method @Deprecated public default java.util.List<java.lang.Integer> arrange(int totalSize, java.util.List<java.lang.Integer> size);
+ method public void arrange(int totalSize, int[] size, androidx.compose.ui.unit.Density density, int[] outPosition);
method public default float getSpacing();
property public default float spacing;
}
diff --git a/compose/foundation/foundation-layout/api/restricted_current.txt b/compose/foundation/foundation-layout/api/restricted_current.txt
index 2806d37..7b36eca9 100644
--- a/compose/foundation/foundation-layout/api/restricted_current.txt
+++ b/compose/foundation/foundation-layout/api/restricted_current.txt
@@ -51,8 +51,7 @@
}
@androidx.compose.foundation.layout.InternalLayoutApi public static interface Arrangement.Horizontal {
- method public void arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.unit.Density density, java.util.List<java.lang.Integer> outPosition);
- method @Deprecated public default java.util.List<java.lang.Integer> arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.LayoutDirection layoutDirection);
+ method public void arrange(int totalSize, int[] size, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.unit.Density density, int[] outPosition);
method public default float getSpacing();
property public default float spacing;
}
@@ -62,8 +61,7 @@
}
@androidx.compose.foundation.layout.InternalLayoutApi public static interface Arrangement.Vertical {
- method public void arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.Density density, java.util.List<java.lang.Integer> outPosition);
- method @Deprecated public default java.util.List<java.lang.Integer> arrange(int totalSize, java.util.List<java.lang.Integer> size);
+ method public void arrange(int totalSize, int[] size, androidx.compose.ui.unit.Density density, int[] outPosition);
method public default float getSpacing();
property public default float spacing;
}
@@ -416,7 +414,7 @@
}
public final class RowColumnImplKt {
- method @kotlin.PublishedApi internal static androidx.compose.ui.node.LayoutNode.MeasureBlocks rowColumnMeasureBlocks-GZ6WFlY(androidx.compose.foundation.layout.LayoutOrientation orientation, kotlin.jvm.functions.Function5<? super java.lang.Integer,? super java.util.List<java.lang.Integer>,? super androidx.compose.ui.unit.LayoutDirection,? super androidx.compose.ui.unit.Density,? super java.util.List<java.lang.Integer>,kotlin.Unit> arrangement, float arrangementSpacing, androidx.compose.foundation.layout.SizeMode crossAxisSize, androidx.compose.foundation.layout.CrossAxisAlignment crossAxisAlignment);
+ method @kotlin.PublishedApi internal static androidx.compose.ui.node.LayoutNode.MeasureBlocks rowColumnMeasureBlocks-GZ6WFlY(androidx.compose.foundation.layout.LayoutOrientation orientation, kotlin.jvm.functions.Function5<? super java.lang.Integer,? super int[],? super androidx.compose.ui.unit.LayoutDirection,? super androidx.compose.ui.unit.Density,? super int[],kotlin.Unit> arrangement, float arrangementSpacing, androidx.compose.foundation.layout.SizeMode crossAxisSize, androidx.compose.foundation.layout.CrossAxisAlignment crossAxisAlignment);
}
public final class RowKt {
diff --git a/compose/foundation/foundation-layout/build.gradle b/compose/foundation/foundation-layout/build.gradle
index 93e2980..fa91824 100644
--- a/compose/foundation/foundation-layout/build.gradle
+++ b/compose/foundation/foundation-layout/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/compose/foundation/foundation-layout/integration-tests/layout-demos/build.gradle b/compose/foundation/foundation-layout/integration-tests/layout-demos/build.gradle
index 6517c25..876d95b 100644
--- a/compose/foundation/foundation-layout/integration-tests/layout-demos/build.gradle
+++ b/compose/foundation/foundation-layout/integration-tests/layout-demos/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/foundation/foundation-layout/samples/build.gradle b/compose/foundation/foundation-layout/samples/build.gradle
index 164e5ef..a09a4a1 100644
--- a/compose/foundation/foundation-layout/samples/build.gradle
+++ b/compose/foundation/foundation-layout/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Arrangement.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Arrangement.kt
index e5b433c..9268c68 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Arrangement.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Arrangement.kt
@@ -22,7 +22,6 @@
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.util.fastForEachIndexed
import kotlin.math.min
import kotlin.math.roundToInt
@@ -47,31 +46,19 @@
* Horizontally places the layout children inside the [Row].
*
* @param totalSize Available space that can be occupied by the children.
- * @param size A list of sizes of all children.
+ * @param size An array of sizes of all children.
* @param layoutDirection A layout direction, left-to-right or right-to-left, of the parent
* layout that should be taken into account when determining positions of the children.
* @param density The current density.
- * @param outPosition A preallocated list that should return the calculated positions.
+ * @param outPosition An array of the size of [size] that returns the calculated positions.
*/
fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
)
-
- @Deprecated("Custom arrangements will not be supported anymore. Please use a provided " +
- "one instead, or Spacers.")
- fun arrange(
- totalSize: Int,
- size: List<Int>,
- layoutDirection: LayoutDirection
- ): List<Int> {
- val result = MutableList(size.size) { 0 }
- arrange(totalSize, size, layoutDirection, Density(1f), result)
- return result
- }
}
/**
@@ -88,27 +75,16 @@
* Vertically places the layout children inside the [Column].
*
* @param totalSize Available space that can be occupied by the children.
- * @param size A list of sizes of all children.
+ * @param size An array of sizes of all children.
* @param density The current density.
- * @param outPosition A preallocated list that should return the calculated positions.
+ * @param outPosition An array of the size of [size] that returns the calculated positions.
*/
fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
)
-
- @Deprecated("Custom arrangements will not be supported anymore. Please use a provided " +
- "one instead, or Spacers.")
- fun arrange(
- totalSize: Int,
- size: List<Int>
- ): List<Int> {
- val result = MutableList(size.size) { 0 }
- arrange(totalSize, size, Density(1f), result)
- return result
- }
}
/**
@@ -130,14 +106,15 @@
val Start = object : Horizontal {
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = if (layoutDirection == LayoutDirection.Ltr) {
placeLeftOrTop(size, outPosition)
} else {
- placeRightOrBottom(totalSize, size.asReversed(), outPosition)
+ size.reverse()
+ placeRightOrBottom(totalSize, size, outPosition)
outPosition.reverse()
}
}
@@ -149,14 +126,15 @@
val End = object : Horizontal {
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = if (layoutDirection == LayoutDirection.Ltr) {
placeRightOrBottom(totalSize, size, outPosition)
} else {
- placeLeftOrTop(size.asReversed(), outPosition)
+ size.reverse()
+ placeLeftOrTop(size, outPosition)
outPosition.reverse()
}
}
@@ -168,9 +146,9 @@
val Top = object : Vertical {
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = placeLeftOrTop(size, outPosition)
}
@@ -181,9 +159,9 @@
val Bottom = object : Vertical {
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = placeRightOrBottom(totalSize, size, outPosition)
}
@@ -195,22 +173,23 @@
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = if (layoutDirection == LayoutDirection.Ltr) {
placeCenter(totalSize, size, outPosition)
} else {
- placeCenter(totalSize, size.asReversed(), outPosition)
+ size.reverse()
+ placeCenter(totalSize, size, outPosition)
outPosition.reverse()
}
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = placeCenter(totalSize, size, outPosition)
}
@@ -223,22 +202,23 @@
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = if (layoutDirection == LayoutDirection.Ltr) {
placeSpaceEvenly(totalSize, size, outPosition)
} else {
- placeSpaceEvenly(totalSize, size.asReversed(), outPosition)
+ size.reverse()
+ placeSpaceEvenly(totalSize, size, outPosition)
outPosition.reverse()
}
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = placeSpaceEvenly(totalSize, size, outPosition)
}
@@ -251,22 +231,23 @@
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = if (layoutDirection == LayoutDirection.Ltr) {
placeSpaceBetween(totalSize, size, outPosition)
} else {
- placeSpaceBetween(totalSize, size.asReversed(), outPosition)
+ size.reverse()
+ placeSpaceBetween(totalSize, size, outPosition)
outPosition.reverse()
}
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = placeSpaceBetween(totalSize, size, outPosition)
}
@@ -280,22 +261,23 @@
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = if (layoutDirection == LayoutDirection.Ltr) {
placeSpaceAround(totalSize, size, outPosition)
} else {
- placeSpaceAround(totalSize, size.asReversed(), outPosition)
+ size.reverse()
+ placeSpaceAround(totalSize, size, outPosition)
outPosition.reverse()
}
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = placeSpaceAround(totalSize, size, outPosition)
}
@@ -368,22 +350,22 @@
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) {
if (size.isEmpty()) return
val spacePx = with(density) { space.toIntPx() }
var occupied = 0
var lastSpace = 0
- (if (layoutDirection == LayoutDirection.Ltr || !rtlMirror) size else size.asReversed())
- .fastForEachIndexed { index, it ->
- outPosition[index] = min(occupied, totalSize - it)
- lastSpace = min(spacePx, totalSize - outPosition[index] - it)
- occupied = outPosition[index] + it + lastSpace
- }
+ if (layoutDirection == LayoutDirection.Rtl && rtlMirror) size.reverse()
+ size.forEachIndexed { index, it ->
+ outPosition[index] = min(occupied, totalSize - it)
+ lastSpace = min(spacePx, totalSize - outPosition[index] - it)
+ occupied = outPosition[index] + it + lastSpace
+ }
occupied -= lastSpace
if (alignment != null && occupied < totalSize) {
@@ -398,53 +380,53 @@
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = arrange(totalSize, size, LayoutDirection.Ltr, density, outPosition)
}
internal fun placeRightOrBottom(
totalSize: Int,
- size: List<Int>,
- outPosition: MutableList<Int>
+ size: IntArray,
+ outPosition: IntArray
) {
val consumedSize = size.fold(0) { a, b -> a + b }
var current = totalSize - consumedSize
- size.fastForEachIndexed { index, it ->
+ size.forEachIndexed { index, it ->
outPosition[index] = current
current += it
}
}
- internal fun placeLeftOrTop(size: List<Int>, outPosition: MutableList<Int>) {
+ internal fun placeLeftOrTop(size: IntArray, outPosition: IntArray) {
var current = 0
- size.fastForEachIndexed { index, it ->
+ size.forEachIndexed { index, it ->
outPosition[index] = current
current += it
}
}
- internal fun placeCenter(totalSize: Int, size: List<Int>, outPosition: MutableList<Int>) {
+ internal fun placeCenter(totalSize: Int, size: IntArray, outPosition: IntArray) {
val consumedSize = size.fold(0) { a, b -> a + b }
var current = (totalSize - consumedSize).toFloat() / 2
- size.fastForEachIndexed { index, it ->
+ size.forEachIndexed { index, it ->
outPosition[index] = current.roundToInt()
current += it.toFloat()
}
}
- internal fun placeSpaceEvenly(totalSize: Int, size: List<Int>, outPosition: MutableList<Int>) {
+ internal fun placeSpaceEvenly(totalSize: Int, size: IntArray, outPosition: IntArray) {
val consumedSize = size.fold(0) { a, b -> a + b }
val gapSize = (totalSize - consumedSize).toFloat() / (size.size + 1)
var current = gapSize
- size.fastForEachIndexed { index, it ->
+ size.forEachIndexed { index, it ->
outPosition[index] = current.roundToInt()
current += it.toFloat() + gapSize
}
}
- internal fun placeSpaceBetween(totalSize: Int, size: List<Int>, outPosition: MutableList<Int>) {
+ internal fun placeSpaceBetween(totalSize: Int, size: IntArray, outPosition: IntArray) {
val consumedSize = size.fold(0) { a, b -> a + b }
val gapSize = if (size.size > 1) {
(totalSize - consumedSize).toFloat() / (size.size - 1)
@@ -452,13 +434,13 @@
0f
}
var current = 0f
- size.fastForEachIndexed { index, it ->
+ size.forEachIndexed { index, it ->
outPosition[index] = current.roundToInt()
current += it.toFloat() + gapSize
}
}
- internal fun placeSpaceAround(totalSize: Int, size: List<Int>, outPosition: MutableList<Int>) {
+ internal fun placeSpaceAround(totalSize: Int, size: IntArray, outPosition: IntArray) {
val consumedSize = size.fold(0) { a, b -> a + b }
val gapSize = if (size.isNotEmpty()) {
(totalSize - consumedSize).toFloat() / size.size
@@ -466,7 +448,7 @@
0f
}
var current = gapSize / 2
- size.fastForEachIndexed { index, it ->
+ size.forEachIndexed { index, it ->
outPosition[index] = current.roundToInt()
current += it.toFloat() + gapSize
}
@@ -486,10 +468,10 @@
val Left = object : Arrangement.Horizontal {
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = Arrangement.placeLeftOrTop(size, outPosition)
}
@@ -502,10 +484,10 @@
val Center = object : Arrangement.Horizontal {
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = Arrangement.placeCenter(totalSize, size, outPosition)
}
@@ -519,10 +501,10 @@
val Right = object : Arrangement.Horizontal {
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = Arrangement.placeRightOrBottom(totalSize, size, outPosition)
}
@@ -536,10 +518,10 @@
val SpaceBetween = object : Arrangement.Horizontal {
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = Arrangement.placeSpaceBetween(totalSize, size, outPosition)
}
@@ -553,10 +535,10 @@
val SpaceEvenly = object : Arrangement.Horizontal {
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = Arrangement.placeSpaceEvenly(totalSize, size, outPosition)
}
@@ -571,10 +553,10 @@
val SpaceAround = object : Arrangement.Horizontal {
override fun arrange(
totalSize: Int,
- size: List<Int>,
+ size: IntArray,
layoutDirection: LayoutDirection,
density: Density,
- outPosition: MutableList<Int>
+ outPosition: IntArray
) = Arrangement.placeSpaceAround(totalSize, size, outPosition)
}
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Flow.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Flow.kt
index 9b854c8..34f2ed9 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Flow.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Flow.kt
@@ -229,8 +229,8 @@
layout(layoutWidth, layoutHeight) {
sequences.fastForEachIndexed { i, placeables ->
- val childrenMainAxisSizes = placeables.mapIndexed { j, placeable ->
- placeable.mainAxisSize() +
+ val childrenMainAxisSizes = IntArray(placeables.size) { j ->
+ placeables[j].mainAxisSize() +
if (j < placeables.lastIndex) mainAxisSpacing.toIntPx() else 0
}
val arrangement = if (i < sequences.lastIndex) {
@@ -240,7 +240,7 @@
}
// TODO(soboleva): rtl support
// Handle vertical direction
- val mainAxisPositions = MutableList(childrenMainAxisSizes.size) { 0 }
+ val mainAxisPositions = IntArray(childrenMainAxisSizes.size) { 0 }
arrangement.arrange(
mainAxisLayoutSize,
childrenMainAxisSizes,
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
index 85a1b54..d915287 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
@@ -44,7 +44,7 @@
@OptIn(ExperimentalLayoutNodeApi::class)
internal fun rowColumnMeasureBlocks(
orientation: LayoutOrientation,
- arrangement: (Int, List<Int>, LayoutDirection, Density, MutableList<Int>) -> Unit,
+ arrangement: (Int, IntArray, LayoutDirection, Density, IntArray) -> Unit,
arrangementSpacing: Dp,
crossAxisSize: SizeMode,
crossAxisAlignment: CrossAxisAlignment
@@ -222,9 +222,11 @@
mainAxisLayoutSize
}
- val mainAxisPositions = MutableList(measurables.size) { 0 }
+ val mainAxisPositions = IntArray(measurables.size) { 0 }
layout(layoutWidth, layoutHeight) {
- val childrenMainAxisSize = placeables.map { it!!.mainAxisSize() }
+ val childrenMainAxisSize = IntArray(measurables.size) { index ->
+ placeables[index]!!.mainAxisSize()
+ }
arrangement(
mainAxisLayoutSize,
childrenMainAxisSize,
diff --git a/compose/foundation/foundation-text/build.gradle b/compose/foundation/foundation-text/build.gradle
index a88b8d4..07b7156 100644
--- a/compose/foundation/foundation-text/build.gradle
+++ b/compose/foundation/foundation-text/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/build.gradle b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/build.gradle
index d35f2a8..72dd6fb 100644
--- a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/build.gradle
+++ b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/build.gradle
@@ -10,7 +10,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/foundation/foundation-text/samples/build.gradle b/compose/foundation/foundation-text/samples/build.gradle
index c345b51..5647372 100644
--- a/compose/foundation/foundation-text/samples/build.gradle
+++ b/compose/foundation/foundation-text/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt
index a3554eb..a0025c7 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt
@@ -32,7 +32,7 @@
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Paint
-import androidx.compose.ui.graphics.drawscope.drawCanvas
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.globalPosition
import androidx.compose.ui.onPositioned
@@ -138,7 +138,7 @@
children = { InlineChildren(text, inlineComposables) },
modifier = modifier.drawLayer().drawBehind {
state.layoutResult?.let { layoutResult ->
- drawCanvas { canvas, _ ->
+ drawIntoCanvas { canvas ->
state.selectionRange?.let {
TextDelegate.paintBackground(
it.min,
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
index 5548cda..4c51453 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
@@ -43,7 +43,7 @@
import androidx.compose.ui.gesture.dragGestureFilter
import androidx.compose.ui.gesture.longPressDragGestureFilter
import androidx.compose.ui.gesture.pressIndicatorGestureFilter
-import androidx.compose.ui.graphics.drawscope.drawCanvas
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.onPositioned
import androidx.compose.ui.platform.ClipboardManagerAmbient
@@ -274,7 +274,7 @@
val drawModifier = Modifier.drawBehind {
state.layoutResult?.let { layoutResult ->
- drawCanvas { canvas, _ ->
+ drawIntoCanvas { canvas ->
TextFieldDelegate.draw(
canvas,
value,
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
index 4331f9e..b038486 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
@@ -26,7 +26,6 @@
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.InternalTextApi
import androidx.compose.ui.text.Paragraph
-import androidx.compose.ui.text.ParagraphConstraints
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextDelegate
import androidx.compose.ui.text.TextLayoutResult
@@ -79,7 +78,7 @@
ellipsis = false,
density = density,
resourceLoader = resourceLoader,
- constraints = ParagraphConstraints(width = Float.POSITIVE_INFINITY)
+ width = Float.POSITIVE_INFINITY
).height.toIntPx()
}
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
index 7658b5e..9441450 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
@@ -255,7 +255,7 @@
clipboardManager?.setText(AnnotatedString(value.getSelectedText()))
- val newCursorOffset = value.selection.end
+ val newCursorOffset = value.selection.max
val newValue = TextFieldValue(
text = value.text,
selection = TextRange(newCursorOffset, newCursorOffset)
@@ -279,7 +279,7 @@
val newText = value.getTextBeforeSelection(value.text.length) +
text +
value.getTextAfterSelection(value.text.length)
- val newCursorOffset = value.selection.start + text.length
+ val newCursorOffset = value.selection.min + text.length
val newValue = TextFieldValue(
text = newText,
@@ -305,7 +305,7 @@
val newText = value.getTextBeforeSelection(value.text.length) +
value.getTextAfterSelection(value.text.length)
- val newCursorOffset = value.selection.start
+ val newCursorOffset = value.selection.min
val newValue = TextFieldValue(
text = newText,
diff --git a/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt b/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt
index 2b4d599..fbaf29f 100644
--- a/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt
+++ b/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt
@@ -49,6 +49,8 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import org.mockito.invocation.InvocationOnMock
+import org.mockito.stubbing.Answer
@SmallTest
@RunWith(JUnit4::class)
@@ -106,8 +108,10 @@
beginOffset
)
whenever(state.layoutResult!!.getOffsetForPosition(dragDistance)).thenReturn(dragOffset)
- whenever(state.layoutResult!!.getWordBoundary(beginOffset)).thenReturn(fakeTextRange)
- whenever(state.layoutResult!!.getWordBoundary(dragOffset)).thenReturn(dragTextRange)
+ whenever(state.layoutResult!!.getWordBoundary(beginOffset))
+ .thenAnswer(TextRangeAnswer(fakeTextRange))
+ whenever(state.layoutResult!!.getWordBoundary(dragOffset))
+ .thenAnswer(TextRangeAnswer(dragTextRange))
whenever(state.layoutResult!!.getBidiRunDirection(any()))
.thenReturn(ResolvedTextDirection.Ltr)
whenever(state.layoutResult!!.getBoundingBox(any())).thenReturn(Rect.Zero)
@@ -285,6 +289,20 @@
}
@Test
+ fun copy_selection_reversed() {
+ manager.value = TextFieldValue(
+ text = text,
+ selection = TextRange("Hello".length, "He".length)
+ )
+
+ manager.copy()
+
+ verify(clipboardManager, times(1)).setText(AnnotatedString("llo"))
+ assertThat(value.selection).isEqualTo(TextRange("Hello".length, "Hello".length))
+ assertThat(state.selectionIsOn).isFalse()
+ }
+
+ @Test
fun paste_clipBoardManager_null() {
manager.clipboardManager = null
@@ -318,6 +336,21 @@
}
@Test
+ fun paste_selection_reversed() {
+ whenever(clipboardManager.getText()).thenReturn(AnnotatedString("i"))
+ manager.value = TextFieldValue(
+ text = text,
+ selection = TextRange("Hello".length, "H".length)
+ )
+
+ manager.paste()
+
+ assertThat(value.text).isEqualTo("Hi World")
+ assertThat(value.selection).isEqualTo(TextRange("Hi".length, "Hi".length))
+ assertThat(state.selectionIsOn).isFalse()
+ }
+
+ @Test
fun cut_selection_collapse() {
manager.value = TextFieldValue(text = text, selection = TextRange(4, 4))
@@ -342,6 +375,21 @@
}
@Test
+ fun cut_selection_reversed() {
+ manager.value = TextFieldValue(
+ text = text,
+ selection = TextRange("Hello".length, "He".length)
+ )
+
+ manager.cut()
+
+ verify(clipboardManager, times(1)).setText(AnnotatedString("llo"))
+ assertThat(value.text).isEqualTo("He World")
+ assertThat(value.selection).isEqualTo(TextRange("He".length, "He".length))
+ assertThat(state.selectionIsOn).isFalse()
+ }
+
+ @Test
fun showSelectionToolbar_trigger_textToolbar_showMenu_Clipboard_empty_not_show_paste() {
manager.value = TextFieldValue(
text = text + text,
@@ -381,3 +429,9 @@
assertThat(manager.isTextChanged()).isFalse()
}
}
+
+// This class is a workaround for the bug that mockito can't stub a method returning inline class.
+// (https://github.com/nhaarman/mockito-kotlin/issues/309).
+internal class TextRangeAnswer(private val textRange: TextRange) : Answer<Any> {
+ override fun answer(invocation: InvocationOnMock?): Any = textRange.packedValue
+}
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index 419cd2e7..f5c2286 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -68,7 +68,7 @@
}
public final class DarkThemeKt {
- method @androidx.compose.runtime.Composable public static boolean isSystemInDarkTheme();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ComposableContract(readonly=true) public static boolean isSystemInDarkTheme();
}
@kotlin.RequiresOptIn(message="This foundation API is experimental and is likely to change or be removed in the " + "future.") public @interface ExperimentalFoundationApi {
@@ -297,6 +297,9 @@
public final class LazyForStateKt {
}
+ public final class LazyGridKt {
+ }
+
@androidx.compose.runtime.Stable public interface LazyItemScope {
method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier);
method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier);
diff --git a/compose/foundation/foundation/api/public_plus_experimental_current.txt b/compose/foundation/foundation/api/public_plus_experimental_current.txt
index 419cd2e7..f5c2286 100644
--- a/compose/foundation/foundation/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation/api/public_plus_experimental_current.txt
@@ -68,7 +68,7 @@
}
public final class DarkThemeKt {
- method @androidx.compose.runtime.Composable public static boolean isSystemInDarkTheme();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ComposableContract(readonly=true) public static boolean isSystemInDarkTheme();
}
@kotlin.RequiresOptIn(message="This foundation API is experimental and is likely to change or be removed in the " + "future.") public @interface ExperimentalFoundationApi {
@@ -297,6 +297,9 @@
public final class LazyForStateKt {
}
+ public final class LazyGridKt {
+ }
+
@androidx.compose.runtime.Stable public interface LazyItemScope {
method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier);
method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier);
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index 419cd2e7..f5c2286 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -68,7 +68,7 @@
}
public final class DarkThemeKt {
- method @androidx.compose.runtime.Composable public static boolean isSystemInDarkTheme();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ComposableContract(readonly=true) public static boolean isSystemInDarkTheme();
}
@kotlin.RequiresOptIn(message="This foundation API is experimental and is likely to change or be removed in the " + "future.") public @interface ExperimentalFoundationApi {
@@ -297,6 +297,9 @@
public final class LazyForStateKt {
}
+ public final class LazyGridKt {
+ }
+
@androidx.compose.runtime.Stable public interface LazyItemScope {
method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier);
method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier);
diff --git a/compose/foundation/foundation/build.gradle b/compose/foundation/foundation/build.gradle
index da3d897..51cea41 100644
--- a/compose/foundation/foundation/build.gradle
+++ b/compose/foundation/foundation/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/build.gradle b/compose/foundation/foundation/integration-tests/foundation-demos/build.gradle
index d24890c..2575b16 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/build.gradle
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/foundation/foundation/samples/build.gradle b/compose/foundation/foundation/samples/build.gradle
index 46852b9..564f3f3 100644
--- a/compose/foundation/foundation/samples/build.gradle
+++ b/compose/foundation/foundation/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyGridTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyGridTest.kt
new file mode 100644
index 0000000..f3f349a
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyGridTest.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2020 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 androidx.compose.foundation.lazy
+
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.preferredHeight
+import androidx.compose.foundation.layout.preferredSize
+import androidx.compose.foundation.layout.preferredWidth
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.unit.dp
+import androidx.test.filters.MediumTest
+import androidx.ui.test.assertIsDisplayed
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.onNodeWithTag
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@MediumTest
+@RunWith(JUnit4::class)
+class LazyGridTest {
+ private val LazyGridTag = "LazyGridTag"
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun lazyGridShowsOneItem() {
+ val itemTestTag = "itemTestTag"
+
+ rule.setContent {
+ LazyGrid(
+ columns = 3
+ ) {
+ item {
+ Spacer(
+ Modifier.preferredSize(10.dp).testTag(itemTestTag)
+ )
+ }
+ }
+ }
+
+ rule.onNodeWithTag(itemTestTag)
+ .assertIsDisplayed()
+ }
+
+ @Test
+ fun lazyGridShowsOneRow() {
+ val items = (1..5).map { it.toString() }
+
+ rule.setContent {
+ LazyGrid(
+ columns = 3,
+ modifier = Modifier.preferredHeight(100.dp).preferredWidth(300.dp)
+ ) {
+ items(items) {
+ Spacer(Modifier.preferredHeight(101.dp).testTag(it))
+ }
+ }
+ }
+
+ rule.onNodeWithTag("1")
+ .assertIsDisplayed()
+
+ rule.onNodeWithTag("2")
+ .assertIsDisplayed()
+
+ rule.onNodeWithTag("3")
+ .assertIsDisplayed()
+
+ rule.onNodeWithTag("4")
+ .assertDoesNotExist()
+
+ rule.onNodeWithTag("5")
+ .assertDoesNotExist()
+ }
+
+ @Test
+ fun lazyGridShowsSecondRowOnScroll() {
+ val items = (1..9).map { it.toString() }
+
+ rule.setContent {
+ LazyGrid(
+ columns = 3,
+ modifier = Modifier.preferredHeight(100.dp).testTag(LazyGridTag)
+ ) {
+ items(items) {
+ Spacer(Modifier.preferredHeight(101.dp).testTag(it))
+ }
+ }
+ }
+
+ rule.onNodeWithTag(LazyGridTag)
+ .scrollBy(y = 50.dp, density = rule.density)
+
+ rule.onNodeWithTag("4")
+ .assertIsDisplayed()
+
+ rule.onNodeWithTag("5")
+ .assertIsDisplayed()
+
+ rule.onNodeWithTag("6")
+ .assertIsDisplayed()
+
+ rule.onNodeWithTag("7")
+ .assertDoesNotExist()
+
+ rule.onNodeWithTag("8")
+ .assertDoesNotExist()
+
+ rule.onNodeWithTag("9")
+ .assertDoesNotExist()
+ }
+
+ @Test
+ fun lazyGridScrollHidesFirstRow() {
+ val items = (1..9).map { it.toString() }
+
+ rule.setContent {
+ LazyGrid(
+ columns = 3,
+ modifier = Modifier.preferredHeight(200.dp).testTag(LazyGridTag)
+ ) {
+ items(items) {
+ Spacer(Modifier.preferredHeight(101.dp).testTag(it))
+ }
+ }
+ }
+
+ rule.onNodeWithTag(LazyGridTag)
+ .scrollBy(y = 102.dp, density = rule.density)
+
+ rule.onNodeWithTag("1")
+ .assertDoesNotExist()
+
+ rule.onNodeWithTag("2")
+ .assertDoesNotExist()
+
+ rule.onNodeWithTag("3")
+ .assertDoesNotExist()
+
+ rule.onNodeWithTag("4")
+ .assertIsDisplayed()
+
+ rule.onNodeWithTag("5")
+ .assertIsDisplayed()
+
+ rule.onNodeWithTag("6")
+ .assertIsDisplayed()
+
+ rule.onNodeWithTag("7")
+ .assertIsDisplayed()
+
+ rule.onNodeWithTag("8")
+ .assertIsDisplayed()
+
+ rule.onNodeWithTag("9")
+ .assertIsDisplayed()
+ }
+}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/DarkTheme.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/DarkTheme.kt
index e35ee4c..785c201 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/DarkTheme.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/DarkTheme.kt
@@ -18,6 +18,7 @@
import android.content.res.Configuration
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.ComposableContract
import androidx.compose.ui.platform.ConfigurationAmbient
/**
@@ -42,8 +43,8 @@
* @return `true` if the system is considered to be in 'dark theme'.
*/
@Composable
+@ComposableContract(readonly = true)
fun isSystemInDarkTheme(): Boolean {
- val configuration = ConfigurationAmbient.current
- return (configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration
- .UI_MODE_NIGHT_YES
+ val uiMode = ConfigurationAmbient.current.uiMode
+ return (uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Border.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Border.kt
index 4d135f5..d7bb036 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Border.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Border.kt
@@ -300,7 +300,7 @@
size.height - borderPixelSize * 2
)
innerPath.addOutline(lastShape!!.createOutline(sizeMinusBorder, density))
- innerPath.shift(Offset(borderPixelSize, borderPixelSize))
+ innerPath.translate(Offset(borderPixelSize, borderPixelSize))
// now we calculate the diff between the inner and the outer paths
diffPath.op(outerPath, innerPath, PathOperation.difference)
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
index 7d2b287..c259476 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
@@ -53,8 +53,11 @@
import androidx.compose.ui.gesture.scrollorientationlocking.Orientation
import androidx.compose.ui.platform.AnimationClockAmbient
import androidx.compose.ui.platform.LayoutDirectionAmbient
+import androidx.compose.ui.semantics.AccessibilityScrollState
import androidx.compose.ui.semantics.scrollBy
import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.horizontalAccessibilityScrollState
+import androidx.compose.ui.semantics.verticalAccessibilityScrollState
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
@@ -364,6 +367,16 @@
) = composed {
val semantics = Modifier.semantics {
if (isScrollable) {
+ val accessibilityScrollState = AccessibilityScrollState(
+ value = state.value,
+ maxValue = state.maxValue,
+ reverseScrolling = reverseScrolling
+ )
+ if (isVertical) {
+ this.verticalAccessibilityScrollState = accessibilityScrollState
+ } else {
+ this.horizontalAccessibilityScrollState = accessibilityScrollState
+ }
// when b/156389287 is fixed, this should be proper scrollTo with reverse handling
scrollBy(action = { x: Float, y: Float ->
if (isVertical) {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyDsl.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyDsl.kt
index 881a67c..e963bcd 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyDsl.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyDsl.kt
@@ -63,13 +63,13 @@
)
}
-private class IntervalHolder(
+internal class IntervalHolder(
val startIndex: Int,
val content: LazyItemScope.(Int) -> (@Composable () -> Unit)
)
-private class LazyListScopeImpl : LazyListScope {
- val intervals = mutableListOf<IntervalHolder>()
+internal class LazyListScopeImpl : LazyListScope {
+ private val intervals = mutableListOf<IntervalHolder>()
var totalSize = 0
fun contentFor(index: Int, scope: LazyItemScope): @Composable () -> Unit {
@@ -220,4 +220,4 @@
) {
index -> scope.contentFor(index, this)
}
-}
\ No newline at end of file
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyGrid.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyGrid.kt
new file mode 100644
index 0000000..0b92f54
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyGrid.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020 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 androidx.compose.foundation.lazy
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Layout
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.dp
+
+/**
+ * The DSL implementation of a lazy grid layout. It composes only visible rows of the grid.
+ * This API is not stable, please consider using stable components like [LazyColumnFor] and [Row]
+ * to achieve the same result.
+ *
+ * @param columns a fixed number of columns of the grid
+ * @param modifier the modifier to apply to this layout
+ * @param contentPadding specify a padding around the whole content
+ * @param content the [LazyListScope] which describes the content
+ */
+@Composable
+internal fun LazyGrid(
+ columns: Int,
+ modifier: Modifier = Modifier,
+ contentPadding: PaddingValues = PaddingValues(0.dp),
+ content: LazyListScope.() -> Unit
+) {
+ val scope = LazyListScopeImpl()
+ scope.apply(content)
+
+ val rows = (scope.totalSize + columns - 1) / columns
+ LazyFor(
+ itemsCount = rows,
+ modifier = modifier,
+ contentPadding = contentPadding,
+ isVertical = true
+ ) { rowIndex ->
+ {
+ GridRow {
+ for (columnIndex in 0 until columns) {
+ val itemIndex = rowIndex * columns + columnIndex
+ if (itemIndex < scope.totalSize) {
+ scope.contentFor(itemIndex, this).invoke()
+ } else {
+ Spacer(Modifier)
+ }
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun GridRow(
+ children: @Composable () -> Unit
+) {
+ // TODO: Implement customisable column widths.
+ Layout(
+ children = children
+ ) { measurables, constraints ->
+
+ // TODO: Avoid int rounding to fill all the width pixels.
+ val itemConstraint = Constraints.fixedWidth(constraints.maxWidth / measurables.size)
+ var maxItemHeight = 0
+ val placeables = measurables.map { measurable ->
+ measurable.measure(itemConstraint)
+ .also {
+ if (it.height > maxItemHeight) {
+ maxItemHeight = it.height
+ }
+ }
+ }
+
+ layout(constraints.maxWidth, maxItemHeight) {
+ var currentXPosition = 0
+ placeables.forEach { placeable ->
+ placeable.placeRelative(x = currentXPosition, y = 0)
+ currentXPosition += placeable.width
+ }
+ }
+ }
+}
diff --git a/compose/integration-tests/benchmark/build.gradle b/compose/integration-tests/benchmark/build.gradle
index 31a7a56..a6dfa41 100644
--- a/compose/integration-tests/benchmark/build.gradle
+++ b/compose/integration-tests/benchmark/build.gradle
@@ -30,7 +30,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation project(":benchmark:benchmark-junit4")
implementation project(":compose:foundation:foundation-layout")
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphBenchmark.kt b/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphBenchmark.kt
index e338cf5..bd15771 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphBenchmark.kt
+++ b/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphBenchmark.kt
@@ -97,11 +97,11 @@
private fun paragraph(
text: String,
spanStyles: List<AnnotatedString.Range<SpanStyle>>,
- constraints: ParagraphConstraints
+ width: Float
): Paragraph {
return Paragraph(
paragraphIntrinsics = paragraphIntrinsics(text, spanStyles),
- constraints = constraints
+ width = width
)
}
@@ -167,7 +167,7 @@
paragraph(
text = annotatedString.text,
spanStyles = annotatedString.spanStyles,
- constraints = ParagraphConstraints(width)
+ width = width
)
}
}
@@ -182,7 +182,7 @@
benchmarkRule.measureRepeated {
val (paragraph, canvas) = runWithTimingDisabled {
val (text, style) = text(textGenerator)
- val paragraph = paragraph(text, style, ParagraphConstraints(width))
+ val paragraph = paragraph(text, style, width)
val canvas = Canvas(
ImageAsset(paragraph.width.roundToInt(), paragraph.height.roundToInt())
)
@@ -202,7 +202,7 @@
val (text, style) = text(textGenerator)
// create a new paragraph and use a smaller width to get
// some line breaking in the result
- val paragraph = paragraph(text, style, ParagraphConstraints(width))
+ val paragraph = paragraph(text, style, width)
val canvas = Canvas(
ImageAsset(paragraph.width.roundToInt(), paragraph.height.roundToInt())
)
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphMethodBenchmark.kt b/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphMethodBenchmark.kt
index 2b0f875..6077d8e 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphMethodBenchmark.kt
+++ b/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphMethodBenchmark.kt
@@ -87,9 +87,7 @@
val paragraphIntrinsics = paragraphIntrinsics(textGenerator, textLength)
return Paragraph(
paragraphIntrinsics = paragraphIntrinsics,
- constraints = ParagraphConstraints(
- width = paragraphIntrinsics.maxIntrinsicWidth / preferredLineCount
- )
+ width = paragraphIntrinsics.maxIntrinsicWidth / preferredLineCount
)
}
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/input/EditProcessorBenchmark.kt b/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/input/EditProcessorBenchmark.kt
index f30d311..04cc171 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/input/EditProcessorBenchmark.kt
+++ b/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/input/EditProcessorBenchmark.kt
@@ -63,8 +63,10 @@
TestScenario(listOf(SetComposingTextEditOp("Android", 1)), "Insert composition"),
TestScenario(listOf(SetComposingRegionEditOp(0, 1)), "Set composition"),
TestScenario(listOf(DeleteSurroundingTextEditOp(0, 1)), "Delete text"),
- TestScenario(listOf(DeleteSurroundingTextInCodePointsEditOp(0, 1)),
- "Delete text in code points"),
+ TestScenario(
+ listOf(DeleteSurroundingTextInCodePointsEditOp(0, 1)),
+ "Delete text in code points"
+ ),
TestScenario(listOf(SetSelectionEditOp(0, 1)), "Set selection"),
TestScenario(listOf(BackspaceKeyEditOp()), "Backspace"),
TestScenario(listOf(MoveCursorEditOp(1)), "Cursor movement")
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt b/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt
index ec1599150..4619d28 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt
+++ b/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt
@@ -96,9 +96,8 @@
rule.activityTestRule.runOnUiThread {
val composeView = rule.findAndroidOwner()
val root = composeView.root
- val selection = root.children[0]
- check(selection.children.size == 1) { "Expecting only a Box" }
- layoutNode = selection.children[0]
+ check(root.children.size == 1) { "Expecting only a Box" }
+ layoutNode = root.children[0]
check(layoutNode.children.isEmpty()) { "Box should be empty" }
}
}
@@ -137,7 +136,8 @@
override fun apply(base: Statement, description: Description?): Statement {
val statement = benchmarkRule.apply(
- activityTestRule.apply(base, description), description!!)
+ activityTestRule.apply(base, description), description!!
+ )
return disableTransitionsRule.apply(statement, description)
}
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/NestedScrollerBenchmark.kt b/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/NestedScrollerBenchmark.kt
index a5e8a97..855abaa 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/NestedScrollerBenchmark.kt
+++ b/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/NestedScrollerBenchmark.kt
@@ -63,20 +63,17 @@
@Test
fun changeScroll_measure() {
- benchmarkRule.toggleStateBenchmarkMeasure(nestedScrollerCaseFactory,
- toggleCausesRecompose = false)
+ benchmarkRule.toggleStateBenchmarkMeasure(nestedScrollerCaseFactory)
}
@Test
fun changeScroll_layout() {
- benchmarkRule.toggleStateBenchmarkLayout(nestedScrollerCaseFactory,
- toggleCausesRecompose = false)
+ benchmarkRule.toggleStateBenchmarkLayout(nestedScrollerCaseFactory)
}
@Test
fun changeScroll_draw() {
- benchmarkRule.toggleStateBenchmarkDraw(nestedScrollerCaseFactory,
- toggleCausesRecompose = false)
+ benchmarkRule.toggleStateBenchmarkDraw(nestedScrollerCaseFactory)
}
@Test
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ScrollerBenchmark.kt b/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ScrollerBenchmark.kt
index 03aca7e..910e55b 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ScrollerBenchmark.kt
+++ b/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ScrollerBenchmark.kt
@@ -63,18 +63,17 @@
@Test
fun changeScroll_measure() {
- benchmarkRule.toggleStateBenchmarkMeasure(scrollerCaseFactory,
- toggleCausesRecompose = false)
+ benchmarkRule.toggleStateBenchmarkMeasure(scrollerCaseFactory)
}
@Test
fun changeScroll_layout() {
- benchmarkRule.toggleStateBenchmarkLayout(scrollerCaseFactory, toggleCausesRecompose = false)
+ benchmarkRule.toggleStateBenchmarkLayout(scrollerCaseFactory)
}
@Test
fun changeScroll_draw() {
- benchmarkRule.toggleStateBenchmarkDraw(scrollerCaseFactory, toggleCausesRecompose = false)
+ benchmarkRule.toggleStateBenchmarkDraw(scrollerCaseFactory)
}
@Test
diff --git a/compose/integration-tests/build.gradle b/compose/integration-tests/build.gradle
index ed23152..a99f159 100644
--- a/compose/integration-tests/build.gradle
+++ b/compose/integration-tests/build.gradle
@@ -30,7 +30,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/integration-tests/demos/build.gradle b/compose/integration-tests/demos/build.gradle
index 7772833..432bfc2 100644
--- a/compose/integration-tests/demos/build.gradle
+++ b/compose/integration-tests/demos/build.gradle
@@ -10,7 +10,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation project(":compose:androidview:androidview:integration-tests:androidview-demos")
implementation project(":compose:animation:animation:integration-tests:animation-demos")
diff --git a/compose/integration-tests/demos/common/build.gradle b/compose/integration-tests/demos/common/build.gradle
index 1024dd3..46b1585 100644
--- a/compose/integration-tests/demos/common/build.gradle
+++ b/compose/integration-tests/demos/common/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
api "androidx.activity:activity:1.2.0-alpha02"
diff --git a/compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/VectorAssetTest.kt b/compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/VectorAssetTest.kt
index 7438ae2..09b34ae 100644
--- a/compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/VectorAssetTest.kt
+++ b/compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/VectorAssetTest.kt
@@ -106,12 +106,28 @@
assertEquals(Color.Blue.toArgb(), getPixel(width / 2, height / 2))
assertEquals(Color.Red.toArgb(), getPixel(insetRectSize + 2, insetRectSize + 2))
- assertEquals(Color.Red.toArgb(), getPixel(width - insetRectSize - 2,
- insetRectSize + 2))
- assertEquals(Color.Red.toArgb(), getPixel(insetRectSize + 2,
- height - insetRectSize - 2))
- assertEquals(Color.Red.toArgb(), getPixel(width - insetRectSize - 2, height -
- insetRectSize - 2))
+ assertEquals(
+ Color.Red.toArgb(),
+ getPixel(
+ width - insetRectSize - 2,
+ insetRectSize + 2
+ )
+ )
+ assertEquals(
+ Color.Red.toArgb(),
+ getPixel(
+ insetRectSize + 2,
+ height - insetRectSize - 2
+ )
+ )
+ assertEquals(
+ Color.Red.toArgb(),
+ getPixel(
+ width - insetRectSize - 2,
+ height -
+ insetRectSize - 2
+ )
+ )
}
}
}
diff --git a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/SimpleRadioButton2TestCase.kt b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/SimpleRadioButton2TestCase.kt
index 651acc6..20fcfae 100644
--- a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/SimpleRadioButton2TestCase.kt
+++ b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/SimpleRadioButton2TestCase.kt
@@ -26,7 +26,7 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.geometry.shift
+import androidx.compose.ui.geometry.translate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Outline
import androidx.compose.ui.graphics.Path
@@ -62,11 +62,13 @@
private fun Outline.offset(size: Float): Outline {
val offset = Offset(size, size)
return when (this) {
- is Outline.Rectangle -> Outline.Rectangle(rect.shift(offset))
- is Outline.Rounded -> Outline.Rounded(roundRect.shift(offset))
- is Outline.Generic -> Outline.Generic(Path().apply {
- addPath(path)
- shift(offset)
- })
+ is Outline.Rectangle -> Outline.Rectangle(rect.translate(offset))
+ is Outline.Rounded -> Outline.Rounded(roundRect.translate(offset))
+ is Outline.Generic -> Outline.Generic(
+ Path().apply {
+ addPath(path)
+ translate(offset)
+ }
+ )
}
}
diff --git a/compose/integration-tests/src/main/java/androidx/ui/integration/test/framework/VectorAssetTestCase.kt b/compose/integration-tests/src/main/java/androidx/ui/integration/test/framework/VectorAssetTestCase.kt
index 8f1e01e..3b55f60 100644
--- a/compose/integration-tests/src/main/java/androidx/ui/integration/test/framework/VectorAssetTestCase.kt
+++ b/compose/integration-tests/src/main/java/androidx/ui/integration/test/framework/VectorAssetTestCase.kt
@@ -45,9 +45,11 @@
@Composable
override fun emitContent() {
Box {
- Box(Modifier.testTag(testTag)
- .preferredSize(24.dp)
- .paint(VectorPainter(getVectorAsset())))
+ Box(
+ Modifier.testTag(testTag)
+ .preferredSize(24.dp)
+ .paint(VectorPainter(getVectorAsset()))
+ )
}
}
diff --git a/compose/material/material-icons-core/samples/build.gradle b/compose/material/material-icons-core/samples/build.gradle
index 138b96b..4d6d462 100644
--- a/compose/material/material-icons-core/samples/build.gradle
+++ b/compose/material/material-icons-core/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/material/material-icons-extended/build.gradle b/compose/material/material-icons-extended/build.gradle
index 2ac2813..6cd7c12 100644
--- a/compose/material/material-icons-extended/build.gradle
+++ b/compose/material/material-icons-extended/build.gradle
@@ -30,7 +30,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/compose/material/material/api/current.txt b/compose/material/material/api/current.txt
index d99fdf3..bb85bfc 100644
--- a/compose/material/material/api/current.txt
+++ b/compose/material/material/api/current.txt
@@ -189,8 +189,12 @@
}
public final class CheckboxKt {
- method @androidx.compose.runtime.Composable public static void Checkbox-D3vZVBM(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long checkedColor = MaterialTheme.colors.secondary, long uncheckedColor = CheckboxConstants.defaultUncheckedColor);
- method @androidx.compose.runtime.Composable public static void TriStateCheckbox-w6h9dZI(androidx.compose.foundation.selection.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long checkMarkColor = CheckboxConstants.animateDefaultCheckmarkColor(state), long boxColor = CheckboxConstants.animateDefaultBoxColor(state, enabled), long borderColor = CheckboxConstants.animateDefaultBorderColor(state, enabled));
+ method @androidx.compose.runtime.Composable public static void Checkbox-JW8VE8g(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long checkedColor = MaterialTheme.colors.secondary, long uncheckedColor = CheckboxConstants.defaultUncheckedColor);
+ method @androidx.compose.runtime.Composable public static void TriStateCheckbox-yIvEug4(androidx.compose.foundation.selection.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long checkMarkColor = CheckboxConstants.animateDefaultCheckmarkColor(state), long boxColor = CheckboxConstants.animateDefaultBoxColor(state, enabled), long borderColor = CheckboxConstants.animateDefaultBorderColor(state, enabled));
}
@androidx.compose.runtime.Stable public final class Colors {
@@ -365,8 +369,12 @@
}
public final class IconButtonKt {
- method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
- method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
+ method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> icon);
+ method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> icon);
}
public final class ListItemKt {
@@ -389,7 +397,9 @@
public final class MenuKt {
method @androidx.compose.runtime.Composable public static void DropdownMenu-iBtHMRc(kotlin.jvm.functions.Function0<kotlin.Unit> toggle, boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, androidx.compose.ui.Modifier toggleModifier = Modifier, long dropdownOffset = Position(0.dp, 0.dp), androidx.compose.ui.Modifier dropdownModifier = Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> dropdownContent);
- method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> content);
}
public final class ModalBottomSheetConstants {
@@ -427,8 +437,12 @@
}
public final class OutlinedTextFieldKt {
- method @androidx.compose.runtime.Composable public static void OutlinedTextField--KhY4tc(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
- method @androidx.compose.runtime.Composable public static void OutlinedTextField-YV8zA4E(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
+ method @androidx.compose.runtime.Composable public static void OutlinedTextField-NT1NBPE(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
+ method @androidx.compose.runtime.Composable public static void OutlinedTextField-OHK2xX0(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
}
public final class ProgressIndicatorConstants {
@@ -457,7 +471,9 @@
}
public final class RadioButtonKt {
- method @androidx.compose.runtime.Composable public static void RadioButton-5r5xgFI(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long color = RadioButtonConstants.animateDefaultColor(selected, enabled));
+ method @androidx.compose.runtime.Composable public static void RadioButton-BNs5H-w(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long color = RadioButtonConstants.animateDefaultColor(selected, enabled));
}
@androidx.compose.runtime.Immutable public final class ResistanceConfig {
@@ -508,7 +524,9 @@
}
public final class SliderKt {
- method @androidx.compose.runtime.Composable public static void Slider-OaNVCSA(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange = 0.0 .. 1.0, @IntRange(from=0) int steps = 0, kotlin.jvm.functions.Function0<kotlin.Unit> onValueChangeEnd = {}, long thumbColor = MaterialTheme.colors.primary, long activeTrackColor = MaterialTheme.colors.primary, long inactiveTrackColor = activeTrackColor.copy(InactiveTrackColorAlpha), long activeTickColor = MaterialTheme.colors.onPrimary.copy(TickColorAlpha), long inactiveTickColor = activeTrackColor.copy(TickColorAlpha));
+ method @androidx.compose.runtime.Composable public static void Slider-B7rb6FQ(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange = 0.0 .. 1.0, @IntRange(from=0) int steps = 0, kotlin.jvm.functions.Function0<kotlin.Unit> onValueChangeEnd = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long thumbColor = MaterialTheme.colors.primary, long activeTrackColor = MaterialTheme.colors.primary, long inactiveTrackColor = activeTrackColor.copy(InactiveTrackColorAlpha), long activeTickColor = MaterialTheme.colors.onPrimary.copy(TickColorAlpha), long inactiveTickColor = activeTrackColor.copy(TickColorAlpha));
}
public final class SnackbarConstants {
@@ -624,7 +642,9 @@
}
public final class SwitchKt {
- method @androidx.compose.runtime.Composable public static void Switch-y3bT5vQ(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long color = MaterialTheme.colors.secondaryVariant);
+ method @androidx.compose.runtime.Composable public static void Switch-vndggBo(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long color = MaterialTheme.colors.secondaryVariant);
}
public final class TabConstants {
@@ -669,8 +689,12 @@
}
public final class TextFieldKt {
- method @androidx.compose.runtime.Composable public static void TextField-enE39lU(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
- method @androidx.compose.runtime.Composable public static void TextField-tHV9mug(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
+ method @androidx.compose.runtime.Composable public static void TextField-LTmrouY(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
+ method @androidx.compose.runtime.Composable public static void TextField-WI3iwFk(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
field public static final float ContainerAlpha = 0.12f;
}
diff --git a/compose/material/material/api/public_plus_experimental_current.txt b/compose/material/material/api/public_plus_experimental_current.txt
index d99fdf3..bb85bfc 100644
--- a/compose/material/material/api/public_plus_experimental_current.txt
+++ b/compose/material/material/api/public_plus_experimental_current.txt
@@ -189,8 +189,12 @@
}
public final class CheckboxKt {
- method @androidx.compose.runtime.Composable public static void Checkbox-D3vZVBM(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long checkedColor = MaterialTheme.colors.secondary, long uncheckedColor = CheckboxConstants.defaultUncheckedColor);
- method @androidx.compose.runtime.Composable public static void TriStateCheckbox-w6h9dZI(androidx.compose.foundation.selection.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long checkMarkColor = CheckboxConstants.animateDefaultCheckmarkColor(state), long boxColor = CheckboxConstants.animateDefaultBoxColor(state, enabled), long borderColor = CheckboxConstants.animateDefaultBorderColor(state, enabled));
+ method @androidx.compose.runtime.Composable public static void Checkbox-JW8VE8g(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long checkedColor = MaterialTheme.colors.secondary, long uncheckedColor = CheckboxConstants.defaultUncheckedColor);
+ method @androidx.compose.runtime.Composable public static void TriStateCheckbox-yIvEug4(androidx.compose.foundation.selection.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long checkMarkColor = CheckboxConstants.animateDefaultCheckmarkColor(state), long boxColor = CheckboxConstants.animateDefaultBoxColor(state, enabled), long borderColor = CheckboxConstants.animateDefaultBorderColor(state, enabled));
}
@androidx.compose.runtime.Stable public final class Colors {
@@ -365,8 +369,12 @@
}
public final class IconButtonKt {
- method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
- method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
+ method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> icon);
+ method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> icon);
}
public final class ListItemKt {
@@ -389,7 +397,9 @@
public final class MenuKt {
method @androidx.compose.runtime.Composable public static void DropdownMenu-iBtHMRc(kotlin.jvm.functions.Function0<kotlin.Unit> toggle, boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, androidx.compose.ui.Modifier toggleModifier = Modifier, long dropdownOffset = Position(0.dp, 0.dp), androidx.compose.ui.Modifier dropdownModifier = Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> dropdownContent);
- method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> content);
}
public final class ModalBottomSheetConstants {
@@ -427,8 +437,12 @@
}
public final class OutlinedTextFieldKt {
- method @androidx.compose.runtime.Composable public static void OutlinedTextField--KhY4tc(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
- method @androidx.compose.runtime.Composable public static void OutlinedTextField-YV8zA4E(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
+ method @androidx.compose.runtime.Composable public static void OutlinedTextField-NT1NBPE(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
+ method @androidx.compose.runtime.Composable public static void OutlinedTextField-OHK2xX0(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
}
public final class ProgressIndicatorConstants {
@@ -457,7 +471,9 @@
}
public final class RadioButtonKt {
- method @androidx.compose.runtime.Composable public static void RadioButton-5r5xgFI(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long color = RadioButtonConstants.animateDefaultColor(selected, enabled));
+ method @androidx.compose.runtime.Composable public static void RadioButton-BNs5H-w(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long color = RadioButtonConstants.animateDefaultColor(selected, enabled));
}
@androidx.compose.runtime.Immutable public final class ResistanceConfig {
@@ -508,7 +524,9 @@
}
public final class SliderKt {
- method @androidx.compose.runtime.Composable public static void Slider-OaNVCSA(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange = 0.0 .. 1.0, @IntRange(from=0) int steps = 0, kotlin.jvm.functions.Function0<kotlin.Unit> onValueChangeEnd = {}, long thumbColor = MaterialTheme.colors.primary, long activeTrackColor = MaterialTheme.colors.primary, long inactiveTrackColor = activeTrackColor.copy(InactiveTrackColorAlpha), long activeTickColor = MaterialTheme.colors.onPrimary.copy(TickColorAlpha), long inactiveTickColor = activeTrackColor.copy(TickColorAlpha));
+ method @androidx.compose.runtime.Composable public static void Slider-B7rb6FQ(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange = 0.0 .. 1.0, @IntRange(from=0) int steps = 0, kotlin.jvm.functions.Function0<kotlin.Unit> onValueChangeEnd = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long thumbColor = MaterialTheme.colors.primary, long activeTrackColor = MaterialTheme.colors.primary, long inactiveTrackColor = activeTrackColor.copy(InactiveTrackColorAlpha), long activeTickColor = MaterialTheme.colors.onPrimary.copy(TickColorAlpha), long inactiveTickColor = activeTrackColor.copy(TickColorAlpha));
}
public final class SnackbarConstants {
@@ -624,7 +642,9 @@
}
public final class SwitchKt {
- method @androidx.compose.runtime.Composable public static void Switch-y3bT5vQ(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long color = MaterialTheme.colors.secondaryVariant);
+ method @androidx.compose.runtime.Composable public static void Switch-vndggBo(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long color = MaterialTheme.colors.secondaryVariant);
}
public final class TabConstants {
@@ -669,8 +689,12 @@
}
public final class TextFieldKt {
- method @androidx.compose.runtime.Composable public static void TextField-enE39lU(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
- method @androidx.compose.runtime.Composable public static void TextField-tHV9mug(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
+ method @androidx.compose.runtime.Composable public static void TextField-LTmrouY(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
+ method @androidx.compose.runtime.Composable public static void TextField-WI3iwFk(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
field public static final float ContainerAlpha = 0.12f;
}
diff --git a/compose/material/material/api/restricted_current.txt b/compose/material/material/api/restricted_current.txt
index d99fdf3..bb85bfc 100644
--- a/compose/material/material/api/restricted_current.txt
+++ b/compose/material/material/api/restricted_current.txt
@@ -189,8 +189,12 @@
}
public final class CheckboxKt {
- method @androidx.compose.runtime.Composable public static void Checkbox-D3vZVBM(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long checkedColor = MaterialTheme.colors.secondary, long uncheckedColor = CheckboxConstants.defaultUncheckedColor);
- method @androidx.compose.runtime.Composable public static void TriStateCheckbox-w6h9dZI(androidx.compose.foundation.selection.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long checkMarkColor = CheckboxConstants.animateDefaultCheckmarkColor(state), long boxColor = CheckboxConstants.animateDefaultBoxColor(state, enabled), long borderColor = CheckboxConstants.animateDefaultBorderColor(state, enabled));
+ method @androidx.compose.runtime.Composable public static void Checkbox-JW8VE8g(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long checkedColor = MaterialTheme.colors.secondary, long uncheckedColor = CheckboxConstants.defaultUncheckedColor);
+ method @androidx.compose.runtime.Composable public static void TriStateCheckbox-yIvEug4(androidx.compose.foundation.selection.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long checkMarkColor = CheckboxConstants.animateDefaultCheckmarkColor(state), long boxColor = CheckboxConstants.animateDefaultBoxColor(state, enabled), long borderColor = CheckboxConstants.animateDefaultBorderColor(state, enabled));
}
@androidx.compose.runtime.Stable public final class Colors {
@@ -365,8 +369,12 @@
}
public final class IconButtonKt {
- method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
- method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
+ method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> icon);
+ method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> icon);
}
public final class ListItemKt {
@@ -389,7 +397,9 @@
public final class MenuKt {
method @androidx.compose.runtime.Composable public static void DropdownMenu-iBtHMRc(kotlin.jvm.functions.Function0<kotlin.Unit> toggle, boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, androidx.compose.ui.Modifier toggleModifier = Modifier, long dropdownOffset = Position(0.dp, 0.dp), androidx.compose.ui.Modifier dropdownModifier = Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> dropdownContent);
- method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> content);
}
public final class ModalBottomSheetConstants {
@@ -427,8 +437,12 @@
}
public final class OutlinedTextFieldKt {
- method @androidx.compose.runtime.Composable public static void OutlinedTextField--KhY4tc(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
- method @androidx.compose.runtime.Composable public static void OutlinedTextField-YV8zA4E(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
+ method @androidx.compose.runtime.Composable public static void OutlinedTextField-NT1NBPE(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
+ method @androidx.compose.runtime.Composable public static void OutlinedTextField-OHK2xX0(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
}
public final class ProgressIndicatorConstants {
@@ -457,7 +471,9 @@
}
public final class RadioButtonKt {
- method @androidx.compose.runtime.Composable public static void RadioButton-5r5xgFI(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long color = RadioButtonConstants.animateDefaultColor(selected, enabled));
+ method @androidx.compose.runtime.Composable public static void RadioButton-BNs5H-w(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long color = RadioButtonConstants.animateDefaultColor(selected, enabled));
}
@androidx.compose.runtime.Immutable public final class ResistanceConfig {
@@ -508,7 +524,9 @@
}
public final class SliderKt {
- method @androidx.compose.runtime.Composable public static void Slider-OaNVCSA(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange = 0.0 .. 1.0, @IntRange(from=0) int steps = 0, kotlin.jvm.functions.Function0<kotlin.Unit> onValueChangeEnd = {}, long thumbColor = MaterialTheme.colors.primary, long activeTrackColor = MaterialTheme.colors.primary, long inactiveTrackColor = activeTrackColor.copy(InactiveTrackColorAlpha), long activeTickColor = MaterialTheme.colors.onPrimary.copy(TickColorAlpha), long inactiveTickColor = activeTrackColor.copy(TickColorAlpha));
+ method @androidx.compose.runtime.Composable public static void Slider-B7rb6FQ(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange = 0.0 .. 1.0, @IntRange(from=0) int steps = 0, kotlin.jvm.functions.Function0<kotlin.Unit> onValueChangeEnd = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long thumbColor = MaterialTheme.colors.primary, long activeTrackColor = MaterialTheme.colors.primary, long inactiveTrackColor = activeTrackColor.copy(InactiveTrackColorAlpha), long activeTickColor = MaterialTheme.colors.onPrimary.copy(TickColorAlpha), long inactiveTickColor = activeTrackColor.copy(TickColorAlpha));
}
public final class SnackbarConstants {
@@ -624,7 +642,9 @@
}
public final class SwitchKt {
- method @androidx.compose.runtime.Composable public static void Switch-y3bT5vQ(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long color = MaterialTheme.colors.secondaryVariant);
+ method @androidx.compose.runtime.Composable public static void Switch-vndggBo(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long color = MaterialTheme.colors.secondaryVariant);
}
public final class TabConstants {
@@ -669,8 +689,12 @@
}
public final class TextFieldKt {
- method @androidx.compose.runtime.Composable public static void TextField-enE39lU(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
- method @androidx.compose.runtime.Composable public static void TextField-tHV9mug(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
+ method @androidx.compose.runtime.Composable public static void TextField-LTmrouY(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
+ method @androidx.compose.runtime.Composable public static void TextField-WI3iwFk(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({
+ return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
field public static final float ContainerAlpha = 0.12f;
}
diff --git a/compose/material/material/build.gradle b/compose/material/material/build.gradle
index ef5e787..fdcbca3 100644
--- a/compose/material/material/build.gradle
+++ b/compose/material/material/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/compose/material/material/integration-tests/material-demos/build.gradle b/compose/material/material/integration-tests/material-demos/build.gradle
index 73503977..52ad8421 100644
--- a/compose/material/material/integration-tests/material-demos/build.gradle
+++ b/compose/material/material/integration-tests/material-demos/build.gradle
@@ -11,7 +11,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
implementation project(":compose:androidview:androidview")
diff --git a/compose/material/material/integration-tests/material-studies/build.gradle b/compose/material/material/integration-tests/material-studies/build.gradle
index 65d7eea..d1b3805 100644
--- a/compose/material/material/integration-tests/material-studies/build.gradle
+++ b/compose/material/material/integration-tests/material-studies/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/material/material/samples/build.gradle b/compose/material/material/samples/build.gradle
index 07e7f20..e0c3d61 100644
--- a/compose/material/material/samples/build.gradle
+++ b/compose/material/material/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
index b10ec7e..44b6e81 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
@@ -16,7 +16,10 @@
package androidx.compose.material.textfield
+import android.content.Context
import android.os.Build
+import android.view.View
+import android.view.inputmethod.InputMethodManager
import androidx.compose.foundation.Box
import androidx.compose.foundation.Text
import androidx.compose.foundation.background
@@ -37,9 +40,12 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus
import androidx.compose.ui.focus.ExperimentalFocus
+import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.isFocused
import androidx.compose.ui.focusObserver
+import androidx.compose.ui.focusRequester
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
@@ -47,6 +53,7 @@
import androidx.compose.ui.node.Ref
import androidx.compose.ui.onPositioned
import androidx.compose.ui.platform.TextInputServiceAmbient
+import androidx.compose.ui.platform.ViewAmbient
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.SoftwareKeyboardController
import androidx.compose.ui.text.input.ImeAction
@@ -182,6 +189,71 @@
}
@Test
+ fun testTextField_showHideKeyboardBasedOnFocus() {
+ val parentFocusRequester = FocusRequester()
+ val focusRequester = FocusRequester()
+ lateinit var hostView: View
+ rule.setMaterialContent {
+ hostView = ViewAmbient.current
+ Box {
+ TextField(
+ modifier = Modifier
+ .focusRequester(parentFocusRequester)
+ .focus()
+ .focusRequester(focusRequester)
+ .testTag(TextfieldTag),
+ value = "input",
+ onValueChange = {},
+ label = {}
+ )
+ }
+ }
+
+ // Shows keyboard when the text field is focused.
+ rule.runOnIdle { focusRequester.requestFocus() }
+ rule.runOnIdle { assertThat(hostView.isSoftwareKeyboardShown).isTrue() }
+
+ // Hides keyboard when the text field is not focused.
+ rule.runOnIdle { parentFocusRequester.requestFocus() }
+ rule.runOnIdle { assertThat(hostView.isSoftwareKeyboardShown).isFalse() }
+ }
+
+ @Test
+ fun testTextField_clickingOnTextAfterDismissingKeyboard_showsKeyboard() {
+ val parentFocusRequester = FocusRequester()
+ val focusRequester = FocusRequester()
+ lateinit var softwareKeyboardController: SoftwareKeyboardController
+ lateinit var hostView: View
+ rule.setMaterialContent {
+ hostView = ViewAmbient.current
+ Box {
+ TextField(
+ modifier = Modifier
+ .focusRequester(parentFocusRequester)
+ .focus()
+ .focusRequester(focusRequester)
+ .testTag(TextfieldTag),
+ value = "input",
+ onValueChange = {},
+ onTextInputStarted = { softwareKeyboardController = it },
+ label = {}
+ )
+ }
+ }
+
+ // Shows keyboard when the text field is focused.
+ rule.runOnIdle { focusRequester.requestFocus() }
+ rule.runOnIdle { assertThat(hostView.isSoftwareKeyboardShown).isTrue() }
+
+ // Hide keyboard.
+ rule.runOnIdle { softwareKeyboardController.hideSoftwareKeyboard() }
+
+ // Clicking on the text field shows the keyboard.
+ rule.onNodeWithTag(TextfieldTag).performClick()
+ rule.runOnIdle { assertThat(hostView.isSoftwareKeyboardShown).isTrue() }
+ }
+
+ @Test
fun testTextField_labelPosition_initial_withDefaultHeight() {
val labelSize = Ref<IntSize>()
val labelPosition = Ref<Offset>()
@@ -797,4 +869,12 @@
rule.onNodeWithTag(TextfieldTag).performClick()
rule.clockTestRule.advanceClock(200L)
}
+
+ private val View.isSoftwareKeyboardShown: Boolean get() {
+ val inputMethodManager =
+ context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+ // TODO(b/163742556): This is just a proxy for software keyboard visibility. Find a better
+ // way to check if the software keyboard is shown.
+ return inputMethodManager.isAcceptingText()
+ }
}
\ No newline at end of file
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AppBar.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AppBar.kt
index 5f97c4f8..86282a4 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AppBar.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AppBar.kt
@@ -236,7 +236,7 @@
val cutoutStartY = -cutoutRadius
addOutline(cutoutShape.createOutline(cutoutSize, density))
- shift(Offset(cutoutStartX, cutoutStartY))
+ translate(Offset(cutoutStartX, cutoutStartY))
// TODO: consider exposing the custom cutout shape instead of just replacing circle shapes?
if (cutoutShape == CircleShape) {
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt
index a362e7e..b7d9f70 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt
@@ -25,6 +25,8 @@
import androidx.compose.animation.core.tween
import androidx.compose.animation.transition
import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
@@ -63,6 +65,10 @@
* @param modifier Modifier to be applied to the layout of the checkbox
* @param enabled enabled whether or not this [Checkbox] will handle input events and appear
* enabled for semantics purposes
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this Checkbox. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this Checkbox in different [Interaction]s.
* @param checkedColor color of the box of the Checkbox when [checked]. See
* [TriStateCheckbox] to fully customize the color of the checkmark / box / border in different
* states.
@@ -76,12 +82,14 @@
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
+ interactionState: InteractionState = remember { InteractionState() },
checkedColor: Color = MaterialTheme.colors.secondary,
uncheckedColor: Color = CheckboxConstants.defaultUncheckedColor
) {
TriStateCheckbox(
state = ToggleableState(checked),
onClick = { onCheckedChange(!checked) },
+ interactionState = interactionState,
enabled = enabled,
boxColor = CheckboxConstants.animateDefaultBoxColor(
state = ToggleableState(checked),
@@ -115,6 +123,10 @@
* @param modifier Modifier to be applied to the layout of the checkbox
* @param enabled whether or not this [TriStateCheckbox] will handle input events and
* appear enabled for semantics purposes
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this TriStateCheckbox. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this TriStateCheckbox in different [Interaction]s.
* @param checkMarkColor color of the check mark of the [TriStateCheckbox]. See
* [CheckboxConstants.animateDefaultCheckmarkColor] for customizing the check mark color in
* different [state]s.
@@ -131,6 +143,7 @@
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
+ interactionState: InteractionState = remember { InteractionState() },
checkMarkColor: Color = CheckboxConstants.animateDefaultCheckmarkColor(state),
boxColor: Color = CheckboxConstants.animateDefaultBoxColor(state, enabled),
borderColor: Color = CheckboxConstants.animateDefaultBorderColor(state, enabled)
@@ -142,6 +155,7 @@
state = state,
onClick = onClick,
enabled = enabled,
+ interactionState = interactionState,
indication = RippleIndication(bounded = false, radius = CheckboxRippleRadius)
)
.padding(CheckboxDefaultPadding),
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt
index 83ab797..1a2f903f 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt
@@ -18,11 +18,14 @@
import androidx.compose.foundation.Box
import androidx.compose.foundation.ContentGravity
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.preferredSize
import androidx.compose.foundation.selection.toggleable
import androidx.compose.material.ripple.RippleIndication
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@@ -44,6 +47,10 @@
* @param modifier optional [Modifier] for this IconButton
* @param enabled whether or not this IconButton will handle input events and appear enabled for
* semantics purposes
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this IconButton. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this IconButton in different [Interaction]s.
* @param icon the content (icon) to be drawn inside the IconButton. This is typically an
* [androidx.compose.foundation.Icon].
*/
@@ -52,6 +59,7 @@
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
+ interactionState: InteractionState = remember { InteractionState() },
icon: @Composable () -> Unit
) {
Box(
@@ -59,6 +67,7 @@
.clickable(
onClick = onClick,
enabled = enabled,
+ interactionState = interactionState,
indication = RippleIndication(bounded = false, radius = RippleRadius)
)
.then(IconButtonSizeModifier),
@@ -78,6 +87,10 @@
* @param modifier optional [Modifier] for this IconToggleButton
* @param enabled enabled whether or not this [IconToggleButton] will handle input events and appear
* enabled for semantics purposes
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this IconToggleButton. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this IconToggleButton in different [Interaction]s.
* @param icon the content (icon) to be drawn inside the IconToggleButton. This is typically an
* [androidx.compose.foundation.Icon].
*/
@@ -87,6 +100,7 @@
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
+ interactionState: InteractionState = remember { InteractionState() },
icon: @Composable () -> Unit
) {
Box(
@@ -94,6 +108,7 @@
value = checked,
onValueChange = onCheckedChange,
enabled = enabled,
+ interactionState = interactionState,
indication = RippleIndication(bounded = false, radius = RippleRadius)
).then(IconButtonSizeModifier),
gravity = ContentGravity.Center,
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt
index 5aa22fe..92deb97 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt
@@ -23,6 +23,8 @@
import androidx.compose.animation.transition
import androidx.compose.foundation.Box
import androidx.compose.foundation.ContentGravity
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
import androidx.compose.foundation.ProvideTextStyle
import androidx.compose.foundation.ScrollableColumn
import androidx.compose.foundation.clickable
@@ -162,18 +164,28 @@
* @param modifier The modifier to be applied to the menu item
* @param enabled Controls the enabled state of the menu item - when `false`, the menu item
* will not be clickable and [onClick] will not be invoked
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this DropdownMenuItem. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this DropdownMenuItem in different [Interaction]s.
*/
@Composable
fun DropdownMenuItem(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
+ interactionState: InteractionState = remember { InteractionState() },
content: @Composable () -> Unit
) {
// TODO(popam, b/156911853): investigate replacing this Box with ListItem
Box(
modifier = modifier
- .clickable(enabled = enabled, onClick = onClick, indication = RippleIndication(true))
+ .clickable(
+ enabled = enabled,
+ onClick = onClick,
+ interactionState = interactionState,
+ indication = RippleIndication(true)
+ )
.fillMaxWidth()
// Preferred min and max width used during the intrinsic measurement.
.preferredSizeIn(
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
index e609011..4f0728a 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
@@ -17,6 +17,8 @@
package androidx.compose.material
import androidx.compose.foundation.Box
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
import androidx.compose.foundation.Text
import androidx.compose.foundation.currentTextStyle
import androidx.compose.foundation.layout.padding
@@ -101,6 +103,10 @@
* input service (e.g. software keyboard on Android) has been established. Called with the
* [SoftwareKeyboardController] instance that can be used to request to show or hide the software
* keyboard
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this OutlinedTextField. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this OutlinedTextField in different [Interaction]s.
* @param activeColor the color of the label, bottom indicator and the cursor when the text field is
* in focus
* @param inactiveColor the color of either the input text or placeholder when the text field is in
@@ -124,6 +130,7 @@
imeAction: ImeAction = ImeAction.Unspecified,
onImeActionPerformed: (ImeAction, SoftwareKeyboardController?) -> Unit = { _, _ -> },
onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
+ interactionState: InteractionState = remember { InteractionState() },
activeColor: Color = MaterialTheme.colors.primary,
inactiveColor: Color = MaterialTheme.colors.onSurface,
errorColor: Color = MaterialTheme.colors.error
@@ -160,6 +167,7 @@
imeAction = imeAction,
onImeActionPerformed = onImeActionPerformed,
onTextInputStarted = onTextInputStarted,
+ interactionState = interactionState,
activeColor = activeColor,
inactiveColor = inactiveColor,
errorColor = errorColor,
@@ -214,6 +222,10 @@
* input service (e.g. software keyboard on Android) has been established. Called with the
* [SoftwareKeyboardController] instance that can be used to request to show or hide the software
* keyboard
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this OutlinedTextField. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this OutlinedTextField in different [Interaction]s.
* @param activeColor the color of the label, bottom indicator and the cursor when the text field is
* in focus
* @param inactiveColor the color of either the input text or placeholder when the text field is in
@@ -237,6 +249,7 @@
imeAction: ImeAction = ImeAction.Unspecified,
onImeActionPerformed: (ImeAction, SoftwareKeyboardController?) -> Unit = { _, _ -> },
onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
+ interactionState: InteractionState = remember { InteractionState() },
activeColor: Color = MaterialTheme.colors.primary,
inactiveColor: Color = MaterialTheme.colors.onSurface,
errorColor: Color = MaterialTheme.colors.error
@@ -257,6 +270,7 @@
imeAction = imeAction,
onImeActionPerformed = onImeActionPerformed,
onTextInputStarted = onTextInputStarted,
+ interactionState = interactionState,
activeColor = activeColor,
inactiveColor = inactiveColor,
errorColor = errorColor,
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ProgressIndicator.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ProgressIndicator.kt
index 8ad5a57..0be2779 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ProgressIndicator.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ProgressIndicator.kt
@@ -101,15 +101,15 @@
initState = 0,
toState = 1
)
- val firstLineHead = state[FirstLineHeadProp]
- val firstLineTail = state[FirstLineTailProp]
- val secondLineHead = state[SecondLineHeadProp]
- val secondLineTail = state[SecondLineTailProp]
Canvas(
modifier
.progressSemantics()
.preferredSize(LinearIndicatorWidth, LinearIndicatorHeight)
) {
+ val firstLineHead = state[FirstLineHeadProp]
+ val firstLineTail = state[FirstLineTailProp]
+ val secondLineHead = state[SecondLineHeadProp]
+ val secondLineTail = state[SecondLineTailProp]
val strokeWidth = ProgressIndicatorConstants.DefaultStrokeWidth.toPx()
drawLinearIndicatorBackground(backgroundColor, strokeWidth)
if (firstLineHead - firstLineTail > 0) {
@@ -213,25 +213,24 @@
initState = 0,
toState = 1
)
- val currentRotation = state[IterationProp]
- val baseRotation = state[BaseRotationProp]
-
- val currentRotationAngleOffset = (currentRotation * RotationAngleOffset) % 360f
-
- var startAngle = state[TailRotationProp]
- val endAngle = state[HeadRotationProp]
- // How long a line to draw using the start angle as a reference point
- val sweep = abs(endAngle - startAngle)
-
- // Offset by the constant offset and the per rotation offset
- startAngle += StartAngleOffset + currentRotationAngleOffset
- startAngle += baseRotation
-
Canvas(
modifier
.progressSemantics()
.preferredSize(CircularIndicatorDiameter)
) {
+ val currentRotation = state[IterationProp]
+ val baseRotation = state[BaseRotationProp]
+
+ val currentRotationAngleOffset = (currentRotation * RotationAngleOffset) % 360f
+
+ var startAngle = state[TailRotationProp]
+ val endAngle = state[HeadRotationProp]
+ // How long a line to draw using the start angle as a reference point
+ val sweep = abs(endAngle - startAngle)
+
+ // Offset by the constant offset and the per rotation offset
+ startAngle += StartAngleOffset + currentRotationAngleOffset
+ startAngle += baseRotation
drawIndeterminateCircularIndicator(startAngle, strokeWidth, sweep, color, stroke)
}
}
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt
index ebfef1b..d4c0983 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt
@@ -19,6 +19,8 @@
import androidx.compose.animation.animate
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
import androidx.compose.foundation.Text
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -28,6 +30,7 @@
import androidx.compose.foundation.selection.selectable
import androidx.compose.material.ripple.RippleIndication
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -52,6 +55,10 @@
* @param modifier Modifier to be applied to the radio button
* @param enabled Controls the enabled state of the [RadioButton]. When `false`, this button will
* not be selectable and appears in the disabled ui state
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this RadioButton. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this RadioButton in different [Interaction]s.
* @param color color of the RadioButton. See [RadioButtonConstants.animateDefaultColor] for
* customizing the color of the RadioButton in one / multiple states, such as when [selected] or
* not [enabled].
@@ -62,6 +69,7 @@
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
+ interactionState: InteractionState = remember { InteractionState() },
color: Color = RadioButtonConstants.animateDefaultColor(selected, enabled)
) {
val dotRadius = animate(
@@ -74,6 +82,7 @@
selected = selected,
onClick = onClick,
enabled = enabled,
+ interactionState = interactionState,
indication = RippleIndication(bounded = false, radius = RadioButtonRippleRadius)
)
.wrapContentSize(Alignment.Center)
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
index 5a1ea8d..2bfa513 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
@@ -99,6 +99,10 @@
* @param onValueChangeEnd lambda to be invoked when value change has ended. This callback
* shouldn't be used to update the slider value (use [onValueChange] for that), but rather to
* know when the user has completed selecting a new value by ending a drag or a click.
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this Slider. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this Slider in different [Interaction]s.
* @param thumbColor color of thumb of the slider
* @param activeTrackColor color of the track in the part that is "active", meaning that the
* thumb is ahead of it
@@ -117,6 +121,7 @@
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
@IntRange(from = 0) steps: Int = 0,
onValueChangeEnd: () -> Unit = {},
+ interactionState: InteractionState = remember { InteractionState() },
thumbColor: Color = MaterialTheme.colors.primary,
activeTrackColor: Color = MaterialTheme.colors.primary,
inactiveTrackColor: Color = activeTrackColor.copy(alpha = InactiveTrackColorAlpha),
@@ -149,8 +154,6 @@
}
}
- val interactionState = remember { InteractionState() }
-
val press = Modifier.pressIndicatorGestureFilter(
onStart = { pos ->
position.holder.snapTo(if (isRtl) maxPx - pos.x else pos.x)
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
index df18725..793f052 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
@@ -57,7 +57,11 @@
* therefore the change of checked state is requested.
* @param modifier Modifier to be applied to the switch layout
* @param enabled whether or not components is enabled and can be clicked to request state change
- * @param color main color of the track and trumb when the Switch is checked
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this Switch. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this Switch in different [Interaction]s.
+ * @param color main color of the track and thumb when the Switch is checked
*/
@Composable
@OptIn(ExperimentalMaterialApi::class)
@@ -66,12 +70,12 @@
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
+ interactionState: InteractionState = remember { InteractionState() },
color: Color = MaterialTheme.colors.secondaryVariant
) {
val minBound = 0f
val maxBound = with(DensityAmbient.current) { ThumbPathLength.toPx() }
val swipeableState = rememberSwipeableStateFor(checked, onCheckedChange, AnimationSpec)
- val interactionState = remember { InteractionState() }
val isRtl = LayoutDirectionAmbient.current == LayoutDirection.Rtl
Stack(
modifier
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
index 42c6169..5459021 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
@@ -17,6 +17,8 @@
package androidx.compose.material
import androidx.compose.foundation.Box
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
import androidx.compose.foundation.Text
import androidx.compose.foundation.background
import androidx.compose.foundation.currentTextStyle
@@ -128,6 +130,10 @@
* input service (e.g. software keyboard on Android) has been established. Called with the
* [SoftwareKeyboardController] instance that can be used to request to show or hide the software
* keyboard
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this TextField. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this TextField in different [Interaction]s.
* @param activeColor the color of the label, bottom indicator and the cursor when the text field is
* in focus
* @param inactiveColor the color of either the input text or placeholder when the text field is in
@@ -153,6 +159,7 @@
imeAction: ImeAction = ImeAction.Unspecified,
onImeActionPerformed: (ImeAction, SoftwareKeyboardController?) -> Unit = { _, _ -> },
onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
+ interactionState: InteractionState = remember { InteractionState() },
activeColor: Color = MaterialTheme.colors.primary,
inactiveColor: Color = MaterialTheme.colors.onSurface,
errorColor: Color = MaterialTheme.colors.error,
@@ -191,6 +198,7 @@
imeAction = imeAction,
onImeActionPerformed = onImeActionPerformed,
onTextInputStarted = onTextInputStarted,
+ interactionState = interactionState,
activeColor = activeColor,
inactiveColor = inactiveColor,
errorColor = errorColor,
@@ -247,6 +255,10 @@
* input service (e.g. software keyboard on Android) has been established. Called with the
* [SoftwareKeyboardController] instance that can be used to request to show or hide the software
* keyboard
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this TextField. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this TextField in different [Interaction]s.
* @param activeColor the color of the label, bottom indicator and the cursor when the text field is
* in focus
* @param inactiveColor the color of either the input text or placeholder when the text field is in
@@ -272,6 +284,7 @@
imeAction: ImeAction = ImeAction.Unspecified,
onImeActionPerformed: (ImeAction, SoftwareKeyboardController?) -> Unit = { _, _ -> },
onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
+ interactionState: InteractionState = remember { InteractionState() },
activeColor: Color = MaterialTheme.colors.primary,
inactiveColor: Color = MaterialTheme.colors.onSurface,
errorColor: Color = MaterialTheme.colors.error,
@@ -295,6 +308,7 @@
imeAction = imeAction,
onImeActionPerformed = onImeActionPerformed,
onTextInputStarted = onTextInputStarted,
+ interactionState = interactionState,
activeColor = activeColor,
inactiveColor = inactiveColor,
errorColor = errorColor,
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
index 5cb38ca..da9243e 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
@@ -31,8 +31,9 @@
import androidx.compose.foundation.Box
import androidx.compose.foundation.ContentColorAmbient
import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
import androidx.compose.foundation.ProvideTextStyle
-import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.rememberScrollableController
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.layout.padding
@@ -42,6 +43,7 @@
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.onCommit
import androidx.compose.runtime.remember
import androidx.compose.runtime.savedinstancestate.Saver
import androidx.compose.runtime.savedinstancestate.rememberSavedInstanceState
@@ -61,9 +63,11 @@
import androidx.compose.ui.focusObserver
import androidx.compose.ui.focusRequester
import androidx.compose.ui.gesture.scrollorientationlocking.Orientation
+import androidx.compose.ui.gesture.tapGestureFilter
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.node.Ref
+import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.SoftwareKeyboardController
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.ImeAction
@@ -108,6 +112,7 @@
imeAction: ImeAction,
onImeActionPerformed: (ImeAction, SoftwareKeyboardController?) -> Unit,
onTextInputStarted: (SoftwareKeyboardController) -> Unit,
+ interactionState: InteractionState,
activeColor: Color,
inactiveColor: Color,
errorColor: Color,
@@ -158,10 +163,11 @@
}
val focusRequester = FocusRequester()
+ // TODO(b/168908942): Populate interactionState values.
val textFieldModifier = modifier
.focusRequester(focusRequester)
.focusObserver { isFocused = it.isFocused }
- .clickable(indication = null) {
+ .tapGestureFilter {
focusRequester.requestFocus()
// TODO(b/163109449): Showing and hiding keyboard should be handled by BaseTextField.
// The requestFocus() call here should be enough to trigger the software keyboard.
@@ -170,9 +176,16 @@
// so that it can show or hide the keyboard based on the focus state.
keyboardController.value?.showSoftwareKeyboard()
}
+ .semantics(mergeAllDescendants = true) {}
val emphasisLevels = EmphasisAmbient.current
+ onCommit(interactionState) {
+ onDispose {
+ interactionState.removeInteraction(Interaction.Pressed)
+ }
+ }
+
TextFieldTransitionScope.transition(
inputState = inputState,
showLabel = label != null,
diff --git a/compose/navigation/navigation/build.gradle b/compose/navigation/navigation/build.gradle
index c5d3f94..63b6598 100644
--- a/compose/navigation/navigation/build.gradle
+++ b/compose/navigation/navigation/build.gradle
@@ -30,7 +30,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
api project(":compose:runtime:runtime")
diff --git a/compose/navigation/navigation/integration-tests/navigation-demos/build.gradle b/compose/navigation/navigation/integration-tests/navigation-demos/build.gradle
index af097f4..7464171 100644
--- a/compose/navigation/navigation/integration-tests/navigation-demos/build.gradle
+++ b/compose/navigation/navigation/integration-tests/navigation-demos/build.gradle
@@ -28,7 +28,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
implementation project(":compose:integration-tests:demos:common")
diff --git a/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/BottomBarNavDemo.kt b/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/BottomBarNavDemo.kt
index 1e6e313..fc26e7f 100644
--- a/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/BottomBarNavDemo.kt
+++ b/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/BottomBarNavDemo.kt
@@ -43,19 +43,23 @@
var selectedItem by remember { mutableStateOf(0) }
val items = listOf("Profile", "Dashboard", "Scrollable")
- Scaffold(bottomBar = { BottomNavigation {
- items.forEachIndexed { index, item ->
- BottomNavigationItem(
- icon = { Icon(Icons.Filled.Favorite) },
- label = { Text(item) },
- selected = selectedItem == index,
- onClick = {
- navController.navigate(item)
- selectedItem = index
+ Scaffold(
+ bottomBar = {
+ BottomNavigation {
+ items.forEachIndexed { index, item ->
+ BottomNavigationItem(
+ icon = { Icon(Icons.Filled.Favorite) },
+ label = { Text(item) },
+ selected = selectedItem == index,
+ onClick = {
+ navController.navigate(item)
+ selectedItem = index
+ }
+ )
}
- )
+ }
}
- } }) {
+ ) {
NavHost(navController, startDestination = "Profile") {
composable("Profile") { Profile() }
composable("Dashboard") { Dashboard() }
diff --git a/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/NavigationDemos.kt b/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/NavigationDemos.kt
index d636f6ff..d840f47 100644
--- a/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/NavigationDemos.kt
+++ b/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/NavigationDemos.kt
@@ -19,7 +19,10 @@
import androidx.compose.integration.demos.common.ComposableDemo
import androidx.compose.integration.demos.common.DemoCategory
-val NavigationDemos = DemoCategory("Navigation", listOf(
- ComposableDemo("Basic Nav Demo") { BasicNavDemo() },
- ComposableDemo("Bottom Bar Nav Demo") { BottomBarNavDemo() }
-))
+val NavigationDemos = DemoCategory(
+ "Navigation",
+ listOf(
+ ComposableDemo("Basic Nav Demo") { BasicNavDemo() },
+ ComposableDemo("Bottom Bar Nav Demo") { BottomBarNavDemo() }
+ )
+)
diff --git a/compose/navigation/navigation/samples/build.gradle b/compose/navigation/navigation/samples/build.gradle
index d55fe2e..1025034 100644
--- a/compose/navigation/navigation/samples/build.gradle
+++ b/compose/navigation/navigation/samples/build.gradle
@@ -28,7 +28,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
implementation project(":annotation:annotation-sampled")
diff --git a/compose/navigation/navigation/samples/src/main/java/androidx/compose/navigation/samples/NavigationSamples.kt b/compose/navigation/navigation/samples/src/main/java/androidx/compose/navigation/samples/NavigationSamples.kt
index 601cf1b..f2b51ab 100644
--- a/compose/navigation/navigation/samples/src/main/java/androidx/compose/navigation/samples/NavigationSamples.kt
+++ b/compose/navigation/navigation/samples/src/main/java/androidx/compose/navigation/samples/NavigationSamples.kt
@@ -91,9 +91,11 @@
@Composable
fun NavigateButton(screen: Screen) {
val navController = AmbientNavController.current
- Button(onClick = { navController.navigate(screen.title) },
+ Button(
+ onClick = { navController.navigate(screen.title) },
backgroundColor = LightGray,
- modifier = Modifier.fillMaxWidth()) {
+ modifier = Modifier.fillMaxWidth()
+ ) {
Text(text = "Navigate to " + screen.title)
}
}
diff --git a/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavGraphBuilder.kt b/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavGraphBuilder.kt
index 69ed290..3c8308d 100644
--- a/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavGraphBuilder.kt
+++ b/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavGraphBuilder.kt
@@ -27,7 +27,9 @@
* @param content composable for the destination
*/
fun NavGraphBuilder.composable(id: Any, content: @Composable () -> Unit) {
- addDestination(ComposeNavigator.Destination(provider[ComposeNavigator::class], content).apply {
- setId(generateId(id))
- })
+ addDestination(
+ ComposeNavigator.Destination(provider[ComposeNavigator::class], content).apply {
+ setId(generateId(id))
+ }
+ )
}
diff --git a/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavHost.kt b/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavHost.kt
index b8e25a3..d31cd18 100644
--- a/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavHost.kt
+++ b/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavHost.kt
@@ -49,9 +49,12 @@
startDestination: Any,
builder: NavGraphBuilder.() -> Unit
) {
- NavHost(navController, remember (id, startDestination, builder) {
- navController.createGraph(id, startDestination, builder)
- })
+ NavHost(
+ navController,
+ remember (id, startDestination, builder) {
+ navController.createGraph(id, startDestination, builder)
+ }
+ )
}
/**
diff --git a/compose/runtime/runtime-livedata/build.gradle b/compose/runtime/runtime-livedata/build.gradle
index 825bf92..142fe35 100644
--- a/compose/runtime/runtime-livedata/build.gradle
+++ b/compose/runtime/runtime-livedata/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/runtime/runtime-livedata/samples/build.gradle b/compose/runtime/runtime-livedata/samples/build.gradle
index 0c3adea..7ade3d3 100644
--- a/compose/runtime/runtime-livedata/samples/build.gradle
+++ b/compose/runtime/runtime-livedata/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
implementation project(":annotation:annotation-sampled")
diff --git a/compose/runtime/runtime-rxjava2/build.gradle b/compose/runtime/runtime-rxjava2/build.gradle
index 1afca61..fb12e6c 100644
--- a/compose/runtime/runtime-rxjava2/build.gradle
+++ b/compose/runtime/runtime-rxjava2/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/runtime/runtime-rxjava2/samples/build.gradle b/compose/runtime/runtime-rxjava2/samples/build.gradle
index f2afd19..668ef47 100644
--- a/compose/runtime/runtime-rxjava2/samples/build.gradle
+++ b/compose/runtime/runtime-rxjava2/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
implementation project(":annotation:annotation-sampled")
diff --git a/compose/runtime/runtime-saved-instance-state/build.gradle b/compose/runtime/runtime-saved-instance-state/build.gradle
index 690ee6a..16c20f4 100644
--- a/compose/runtime/runtime-saved-instance-state/build.gradle
+++ b/compose/runtime/runtime-saved-instance-state/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/compose/runtime/runtime-saved-instance-state/samples/build.gradle b/compose/runtime/runtime-saved-instance-state/samples/build.gradle
index 4ead02e..96cd790 100644
--- a/compose/runtime/runtime-saved-instance-state/samples/build.gradle
+++ b/compose/runtime/runtime-saved-instance-state/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/runtime/runtime/api/current.txt b/compose/runtime/runtime/api/current.txt
index 16dd20c..fc91886 100644
--- a/compose/runtime/runtime/api/current.txt
+++ b/compose/runtime/runtime/api/current.txt
@@ -976,6 +976,7 @@
method public void clear(Object target);
method public void dispose();
method public void enableStateUpdatesObserving(boolean enabled);
+ method @org.jetbrains.annotations.TestOnly public void notifyChanges(java.util.Set<?> changes, androidx.compose.runtime.snapshots.Snapshot snapshot);
method public <T> void observeReads(T target, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public void pauseObservingReads(kotlin.jvm.functions.Function0<kotlin.Unit> block);
}
diff --git a/compose/runtime/runtime/api/public_plus_experimental_current.txt b/compose/runtime/runtime/api/public_plus_experimental_current.txt
index 16dd20c..fc91886 100644
--- a/compose/runtime/runtime/api/public_plus_experimental_current.txt
+++ b/compose/runtime/runtime/api/public_plus_experimental_current.txt
@@ -976,6 +976,7 @@
method public void clear(Object target);
method public void dispose();
method public void enableStateUpdatesObserving(boolean enabled);
+ method @org.jetbrains.annotations.TestOnly public void notifyChanges(java.util.Set<?> changes, androidx.compose.runtime.snapshots.Snapshot snapshot);
method public <T> void observeReads(T target, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public void pauseObservingReads(kotlin.jvm.functions.Function0<kotlin.Unit> block);
}
diff --git a/compose/runtime/runtime/api/restricted_current.txt b/compose/runtime/runtime/api/restricted_current.txt
index 1a0ceb6..813ce4e 100644
--- a/compose/runtime/runtime/api/restricted_current.txt
+++ b/compose/runtime/runtime/api/restricted_current.txt
@@ -1016,6 +1016,7 @@
method public void clear(Object target);
method public void dispose();
method public void enableStateUpdatesObserving(boolean enabled);
+ method @org.jetbrains.annotations.TestOnly public void notifyChanges(java.util.Set<?> changes, androidx.compose.runtime.snapshots.Snapshot snapshot);
method public <T> void observeReads(T target, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public void pauseObservingReads(kotlin.jvm.functions.Function0<kotlin.Unit> block);
}
diff --git a/compose/runtime/runtime/build.gradle b/compose/runtime/runtime/build.gradle
index 46b9aae..f60e242 100644
--- a/compose/runtime/runtime/build.gradle
+++ b/compose/runtime/runtime/build.gradle
@@ -29,7 +29,7 @@
id("kotlin-multiplatform")
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
android()
diff --git a/compose/runtime/runtime/compose-runtime-benchmark/build.gradle b/compose/runtime/runtime/compose-runtime-benchmark/build.gradle
index c595169..c3c8206 100644
--- a/compose/runtime/runtime/compose-runtime-benchmark/build.gradle
+++ b/compose/runtime/runtime/compose-runtime-benchmark/build.gradle
@@ -45,7 +45,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
androidTestImplementation(project("::compose:ui:ui"))
androidTestImplementation(project(":compose:foundation:foundation"))
diff --git a/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt
index d5add45..d0ad476 100644
--- a/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt
+++ b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt
@@ -28,34 +28,26 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
+import org.junit.runners.JUnit4
+import kotlin.math.pow
+import kotlin.math.roundToInt
import kotlin.random.Random
@LargeTest
-@RunWith(Parameterized::class)
+@RunWith(JUnit4::class)
@OptIn(ExperimentalComposeApi::class)
-class SnapshotStateObserverBenchmark(
- private val numberOfModels: Int,
- private val numberOfNodes: Int
-) : ComposeBenchmarkBase() {
+class SnapshotStateObserverBenchmark : ComposeBenchmarkBase() {
companion object {
- @JvmStatic
- @Parameterized.Parameters(name = "states = {0}, nodes = {1}")
- fun initParameters(): Array<Any> = arrayOf(
- arrayOf(1000, 1000),
- arrayOf(10000, 100),
- arrayOf(100000, 10),
- arrayOf(100, 1000)
- )
+ private const val ScopeCount = 1000
+ private const val StateCount = 1000
}
private val doNothing: (Int) -> Unit = { _ -> }
private lateinit var stateObserver: SnapshotStateObserver
- private val models = List(numberOfModels) { mutableStateOf(0) }
- private val nodes = List(numberOfNodes) { it }
+ private val models = List(StateCount) { mutableStateOf(0) }
+ private val nodes = List(ScopeCount) { it }
private lateinit var random: Random
- private val numObservations = numberOfModels / 10
@Before
fun setup() {
@@ -86,9 +78,13 @@
fun modelObservation() {
runOnUiThread {
benchmarkRule.measureRepeated {
- random = Random(0)
- val node = nodes[random.nextInt(numberOfNodes)]
- observeForNode(node)
+ runWithTimingDisabled {
+ nodes.forEach { node ->
+ stateObserver.clear(node)
+ }
+ random = Random(0)
+ }
+ setupObservations()
}
}
}
@@ -96,11 +92,21 @@
@Test
fun nestedModelObservation() {
runOnUiThread {
- stateObserver.observeReads(nodes[0], doNothing) {
- benchmarkRule.measureRepeated {
+ val list = mutableListOf<Int>()
+ repeat(10) {
+ list += nodes[random.nextInt(ScopeCount)]
+ }
+ benchmarkRule.measureRepeated {
+ runWithTimingDisabled {
random = Random(0)
- val node = nodes[random.nextInt(numberOfNodes)]
- observeForNode(node)
+ nodes.forEach { node ->
+ stateObserver.clear(node)
+ }
+ }
+ stateObserver.observeReads(nodes[0], doNothing) {
+ list.forEach { node ->
+ observeForNode(node)
+ }
}
}
}
@@ -110,12 +116,28 @@
fun modelClear() {
runOnUiThread {
benchmarkRule.measureRepeated {
- random = Random(0)
- val node = nodes[random.nextInt(numberOfNodes)]
- stateObserver.clear(node)
- runWithTimingDisabled {
- observeForNode(node)
+ nodes.forEach { node ->
+ stateObserver.clear(node)
}
+ random = Random(0)
+ runWithTimingDisabled {
+ setupObservations()
+ }
+ }
+ }
+ }
+
+ @Test
+ fun notifyChanges() {
+ runOnUiThread {
+ val states = mutableSetOf<Int>()
+ repeat(50) {
+ states += random.nextInt(StateCount)
+ }
+ val snapshot: Snapshot = Snapshot.current
+ benchmarkRule.measureRepeated {
+ random = Random(0)
+ stateObserver.notifyChanges(states, snapshot)
}
}
}
@@ -125,9 +147,11 @@
private fun observeForNode(node: Int) {
stateObserver.observeReads(node, doNothing) {
+ // we want between 0-10, with the cluster near 0, but some outliers
+ val numObservations = (10.0.pow(random.nextDouble(2.0)) / 10).roundToInt()
repeat(numObservations) {
// just access the value
- models[random.nextInt(numberOfModels)].value
+ models[random.nextInt(StateCount)].value
}
}
}
diff --git a/compose/runtime/runtime/samples/build.gradle b/compose/runtime/runtime/samples/build.gradle
index ba09b21..6340a27 100644
--- a/compose/runtime/runtime/samples/build.gradle
+++ b/compose/runtime/runtime/samples/build.gradle
@@ -27,7 +27,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
index 3f79db7..ffc46e6 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
@@ -18,6 +18,7 @@
import androidx.compose.runtime.ExperimentalComposeApi
import androidx.compose.runtime.ObserverMap
+import androidx.compose.runtime.TestOnly
@ExperimentalComposeApi
@Suppress("DEPRECATION_ERROR")
@@ -178,6 +179,15 @@
}
/**
+ * This method is only used for testing. It notifies that [changes] have been made on
+ * [snapshot].
+ */
+ @TestOnly
+ fun notifyChanges(changes: Set<Any>, snapshot: Snapshot) {
+ applyObserver(changes, snapshot)
+ }
+
+ /**
* Calls the `onChanged` callback for the given targets.
*/
private fun callOnChanged(targetsArray: Array<List<Any>>) {
diff --git a/compose/test-utils/build.gradle b/compose/test-utils/build.gradle
index e5ed981..7c10786 100644
--- a/compose/test-utils/build.gradle
+++ b/compose/test-utils/build.gradle
@@ -27,7 +27,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/compose/ui/ui-geometry/api/current.txt b/compose/ui/ui-geometry/api/current.txt
index 196e434..c6faa6b 100644
--- a/compose/ui/ui-geometry/api/current.txt
+++ b/compose/ui/ui-geometry/api/current.txt
@@ -104,7 +104,6 @@
method public boolean contains-k-4lQ0M(long offset);
method @androidx.compose.runtime.Immutable public androidx.compose.ui.geometry.Rect copy(float left, float top, float right, float bottom);
method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect deflate(float delta);
- method public androidx.compose.ui.geometry.Rect expandToInclude(androidx.compose.ui.geometry.Rect other);
method public float getBottom();
method public long getBottomCenter();
method public long getBottomLeft();
@@ -128,10 +127,10 @@
method public boolean isEmpty();
method public boolean isFinite();
method public boolean isInfinite();
- method public androidx.compose.ui.geometry.Rect join(androidx.compose.ui.geometry.Rect other);
method public boolean overlaps(androidx.compose.ui.geometry.Rect other);
- method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect shift-k-4lQ0M(long offset);
+ method @Deprecated @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect shift-k-4lQ0M(long offset);
method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect translate(float translateX, float translateY);
+ method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect translate-k-4lQ0M(long offset);
property public final long bottomCenter;
property public final long bottomLeft;
property public final long bottomRight;
@@ -236,11 +235,12 @@
method public static androidx.compose.ui.geometry.Rect middleRect(androidx.compose.ui.geometry.RoundRect);
method public static androidx.compose.ui.geometry.Rect outerRect(androidx.compose.ui.geometry.RoundRect);
method public static androidx.compose.ui.geometry.Rect safeInnerRect(androidx.compose.ui.geometry.RoundRect);
- method public static androidx.compose.ui.geometry.RoundRect shift-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
+ method @Deprecated public static androidx.compose.ui.geometry.RoundRect shift-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
method public static androidx.compose.ui.geometry.RoundRect shrink(androidx.compose.ui.geometry.RoundRect, float delta);
method public static androidx.compose.ui.geometry.Rect tallMiddleRect(androidx.compose.ui.geometry.RoundRect);
method public static long topLeftRadius(androidx.compose.ui.geometry.RoundRect);
method public static long topRightRadius(androidx.compose.ui.geometry.RoundRect);
+ method public static androidx.compose.ui.geometry.RoundRect translate-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
method public static androidx.compose.ui.geometry.Rect wideMiddleRect(androidx.compose.ui.geometry.RoundRect);
method public static androidx.compose.ui.geometry.RoundRect withRadius-Z0w6hBY(androidx.compose.ui.geometry.RoundRect, long radius);
}
diff --git a/compose/ui/ui-geometry/api/public_plus_experimental_current.txt b/compose/ui/ui-geometry/api/public_plus_experimental_current.txt
index 196e434..c6faa6b 100644
--- a/compose/ui/ui-geometry/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-geometry/api/public_plus_experimental_current.txt
@@ -104,7 +104,6 @@
method public boolean contains-k-4lQ0M(long offset);
method @androidx.compose.runtime.Immutable public androidx.compose.ui.geometry.Rect copy(float left, float top, float right, float bottom);
method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect deflate(float delta);
- method public androidx.compose.ui.geometry.Rect expandToInclude(androidx.compose.ui.geometry.Rect other);
method public float getBottom();
method public long getBottomCenter();
method public long getBottomLeft();
@@ -128,10 +127,10 @@
method public boolean isEmpty();
method public boolean isFinite();
method public boolean isInfinite();
- method public androidx.compose.ui.geometry.Rect join(androidx.compose.ui.geometry.Rect other);
method public boolean overlaps(androidx.compose.ui.geometry.Rect other);
- method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect shift-k-4lQ0M(long offset);
+ method @Deprecated @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect shift-k-4lQ0M(long offset);
method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect translate(float translateX, float translateY);
+ method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect translate-k-4lQ0M(long offset);
property public final long bottomCenter;
property public final long bottomLeft;
property public final long bottomRight;
@@ -236,11 +235,12 @@
method public static androidx.compose.ui.geometry.Rect middleRect(androidx.compose.ui.geometry.RoundRect);
method public static androidx.compose.ui.geometry.Rect outerRect(androidx.compose.ui.geometry.RoundRect);
method public static androidx.compose.ui.geometry.Rect safeInnerRect(androidx.compose.ui.geometry.RoundRect);
- method public static androidx.compose.ui.geometry.RoundRect shift-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
+ method @Deprecated public static androidx.compose.ui.geometry.RoundRect shift-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
method public static androidx.compose.ui.geometry.RoundRect shrink(androidx.compose.ui.geometry.RoundRect, float delta);
method public static androidx.compose.ui.geometry.Rect tallMiddleRect(androidx.compose.ui.geometry.RoundRect);
method public static long topLeftRadius(androidx.compose.ui.geometry.RoundRect);
method public static long topRightRadius(androidx.compose.ui.geometry.RoundRect);
+ method public static androidx.compose.ui.geometry.RoundRect translate-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
method public static androidx.compose.ui.geometry.Rect wideMiddleRect(androidx.compose.ui.geometry.RoundRect);
method public static androidx.compose.ui.geometry.RoundRect withRadius-Z0w6hBY(androidx.compose.ui.geometry.RoundRect, long radius);
}
diff --git a/compose/ui/ui-geometry/api/restricted_current.txt b/compose/ui/ui-geometry/api/restricted_current.txt
index 196e434..c6faa6b 100644
--- a/compose/ui/ui-geometry/api/restricted_current.txt
+++ b/compose/ui/ui-geometry/api/restricted_current.txt
@@ -104,7 +104,6 @@
method public boolean contains-k-4lQ0M(long offset);
method @androidx.compose.runtime.Immutable public androidx.compose.ui.geometry.Rect copy(float left, float top, float right, float bottom);
method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect deflate(float delta);
- method public androidx.compose.ui.geometry.Rect expandToInclude(androidx.compose.ui.geometry.Rect other);
method public float getBottom();
method public long getBottomCenter();
method public long getBottomLeft();
@@ -128,10 +127,10 @@
method public boolean isEmpty();
method public boolean isFinite();
method public boolean isInfinite();
- method public androidx.compose.ui.geometry.Rect join(androidx.compose.ui.geometry.Rect other);
method public boolean overlaps(androidx.compose.ui.geometry.Rect other);
- method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect shift-k-4lQ0M(long offset);
+ method @Deprecated @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect shift-k-4lQ0M(long offset);
method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect translate(float translateX, float translateY);
+ method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect translate-k-4lQ0M(long offset);
property public final long bottomCenter;
property public final long bottomLeft;
property public final long bottomRight;
@@ -236,11 +235,12 @@
method public static androidx.compose.ui.geometry.Rect middleRect(androidx.compose.ui.geometry.RoundRect);
method public static androidx.compose.ui.geometry.Rect outerRect(androidx.compose.ui.geometry.RoundRect);
method public static androidx.compose.ui.geometry.Rect safeInnerRect(androidx.compose.ui.geometry.RoundRect);
- method public static androidx.compose.ui.geometry.RoundRect shift-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
+ method @Deprecated public static androidx.compose.ui.geometry.RoundRect shift-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
method public static androidx.compose.ui.geometry.RoundRect shrink(androidx.compose.ui.geometry.RoundRect, float delta);
method public static androidx.compose.ui.geometry.Rect tallMiddleRect(androidx.compose.ui.geometry.RoundRect);
method public static long topLeftRadius(androidx.compose.ui.geometry.RoundRect);
method public static long topRightRadius(androidx.compose.ui.geometry.RoundRect);
+ method public static androidx.compose.ui.geometry.RoundRect translate-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
method public static androidx.compose.ui.geometry.Rect wideMiddleRect(androidx.compose.ui.geometry.RoundRect);
method public static androidx.compose.ui.geometry.RoundRect withRadius-Z0w6hBY(androidx.compose.ui.geometry.RoundRect, long radius);
}
diff --git a/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Rect.kt b/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Rect.kt
index 409b0e1..4eae95f 100644
--- a/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Rect.kt
+++ b/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Rect.kt
@@ -28,26 +28,30 @@
/**
* An immutable, 2D, axis-aligned, floating-point rectangle whose coordinates
* are relative to a given origin.
- *
- * A Rect can be created with one its constructors or from an [Offset] and a
- * [Size] using the `&` operator:
- *
- * ```dart
- * Rect myRect = const Offset(1.0, 2.0) & const Size(3.0, 4.0);
- * ```
*/
@Immutable
data class Rect(
- // The offset of the left edge of this rectangle from the x axis.
+ /**
+ * The offset of the left edge of this rectangle from the x axis.
+ */
@Stable
val left: Float,
- // The offset of the top edge of this rectangle from the y axis.
+
+ /**
+ * The offset of the top edge of this rectangle from the y axis.
+ */
@Stable
val top: Float,
- // The offset of the right edge of this rectangle from the x axis.
+
+ /**
+ * The offset of the right edge of this rectangle from the x axis.
+ */
@Stable
val right: Float,
- // The offset of the bottom edge of this rectangle from the y axis.
+
+ /**
+ * The offset of the bottom edge of this rectangle from the y axis.
+ */
@Stable
val bottom: Float
) {
@@ -108,17 +112,29 @@
* To translate a rectangle by separate x and y components rather than by an
* [Offset], consider [translate].
*/
+ @Deprecated(
+ "Use translate(offset) instead",
+ ReplaceWith("translate(offset)", "androidx.compose.ui.geometry")
+ )
@Stable
fun shift(offset: Offset): Rect {
return Rect(left + offset.x, top + offset.y, right + offset.x, bottom + offset.y)
}
/**
+ * Returns a new rectangle translated by the given offset.
+ *
+ * To translate a rectangle by separate x and y components rather than by an
+ * [Offset], consider [translate].
+ */
+ @Stable
+ fun translate(offset: Offset): Rect {
+ return Rect(left + offset.x, top + offset.y, right + offset.x, bottom + offset.y)
+ }
+
+ /**
* Returns a new rectangle with translateX added to the x components and
* translateY added to the y components.
- *
- * To translate a rectangle by an [Offset] rather than by separate x and y
- * components, consider [shift].
*/
@Stable
fun translate(translateX: Float, translateY: Float): Rect {
@@ -156,31 +172,6 @@
)
}
- /**
- * Returns a new rectangle which is the bounding box containing this
- * rectangle and the given rectangle.
- */
- fun expandToInclude(other: Rect): Rect {
- return Rect(
- min(left, other.left),
- min(top, other.top),
- max(right, other.right),
- max(bottom, other.bottom)
- )
- }
-
- fun join(other: Rect): Rect {
- if (other.isEmpty) {
- // return this if the other params are empty
- return this
- }
- if (isEmpty) {
- // if we are empty, just take other
- return other
- }
- return expandToInclude(other)
- }
-
/** Whether `other` has a nonzero area of overlap with this rectangle. */
fun overlaps(other: Rect): Boolean {
if (right <= other.left || other.right <= left)
diff --git a/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/RoundRect.kt b/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/RoundRect.kt
index 8115573..252067f 100644
--- a/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/RoundRect.kt
+++ b/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/RoundRect.kt
@@ -574,7 +574,13 @@
fun RoundRect.bottomLeftRadius(): Radius = Radius(bottomLeftRadiusX, bottomLeftRadiusY)
/** Returns a new [RoundRect] translated by the given offset. */
-fun RoundRect.shift(offset: Offset): RoundRect = RoundRect(
+@Deprecated("Use translate(offset) instead",
+ ReplaceWith("translate(offset)", "androidx.compose.ui.RoundRect")
+)
+fun RoundRect.shift(offset: Offset): RoundRect = translate(offset)
+
+/** Returns a new [RoundRect] translated by the given offset. */
+fun RoundRect.translate(offset: Offset): RoundRect = RoundRect(
left = left + offset.x,
top = top + offset.y,
right = right + offset.x,
diff --git a/compose/ui/ui-geometry/src/test/kotlin/androidx/compose/ui/geometry/RectTest.kt b/compose/ui/ui-geometry/src/test/kotlin/androidx/compose/ui/geometry/RectTest.kt
index 5edcabaf..ba68d88 100644
--- a/compose/ui/ui-geometry/src/test/kotlin/androidx/compose/ui/geometry/RectTest.kt
+++ b/compose/ui/ui-geometry/src/test/kotlin/androidx/compose/ui/geometry/RectTest.kt
@@ -104,8 +104,8 @@
}
@Test
- fun `rect shift`() {
- val shifted = Rect(0f, 5f, 10f, 15f).shift(Offset(10f, 15f))
+ fun `rect translate offset`() {
+ val shifted = Rect(0f, 5f, 10f, 15f).translate(Offset(10f, 15f))
assertEquals(Rect(10f, 20f, 20f, 30f), shifted)
}
@@ -135,21 +135,6 @@
}
@Test
- fun `rect expandToInclude`() {
- val expanded = Rect(0f, 0f, 20f, 20f).expandToInclude(
- Rect(10f, 10f, 30f, 30f))
- assertEquals(Rect(0f, 0f, 30f, 30f), expanded)
- }
-
- @Test
- fun `rect join`() {
- val rect1 = Rect.Zero
- val rect2 = Rect(12f, 24f, 64f, 128f)
- assertEquals(rect2, rect2.join(rect1))
- assertEquals(rect2, rect1.join(rect2))
- }
-
- @Test
fun `rect overlap`() {
val rect1 = Rect(0f, 5f, 10f, 15f)
val rect2 = Rect(5f, 10f, 15f, 20f)
diff --git a/compose/ui/ui-graphics/api/current.txt b/compose/ui/ui-graphics/api/current.txt
index 37b8fbe..187547b 100644
--- a/compose/ui/ui-graphics/api/current.txt
+++ b/compose/ui/ui-graphics/api/current.txt
@@ -96,7 +96,7 @@
method public void relativeQuadraticBezierTo(float dx1, float dy1, float dx2, float dy2);
method public void reset();
method public void setFillType(androidx.compose.ui.graphics.PathFillType value);
- method public void shift-k-4lQ0M(long offset);
+ method public void translate-k-4lQ0M(long offset);
property public androidx.compose.ui.graphics.PathFillType fillType;
property public boolean isConvex;
property public boolean isEmpty;
@@ -500,7 +500,8 @@
method public void relativeQuadraticBezierTo(float dx1, float dy1, float dx2, float dy2);
method public void reset();
method public void setFillType(androidx.compose.ui.graphics.PathFillType p);
- method public void shift-k-4lQ0M(long offset);
+ method @Deprecated public default void shift-k-4lQ0M(long offset);
+ method public void translate-k-4lQ0M(long offset);
property public abstract androidx.compose.ui.graphics.PathFillType fillType;
property public abstract boolean isConvex;
property public abstract boolean isEmpty;
@@ -880,9 +881,11 @@
public final class DrawScopeKt {
method public static inline void clipPath(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.graphics.Path path, androidx.compose.ui.graphics.ClipOp clipOp = androidx.compose.ui.graphics.ClipOp.Intersect, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void clipRect(androidx.compose.ui.graphics.drawscope.DrawScope, float left = 0.0f, float top = 0.0f, float right = size.width, float bottom = size.height, androidx.compose.ui.graphics.ClipOp clipOp = androidx.compose.ui.graphics.ClipOp.Intersect, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
- method public static inline void drawCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.Canvas,? super androidx.compose.ui.geometry.Size,kotlin.Unit> block);
+ method @Deprecated public static inline void drawCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.Canvas,? super androidx.compose.ui.geometry.Size,kotlin.Unit> block);
+ method public static inline void drawIntoCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.Canvas,kotlin.Unit> block);
method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
- method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float dx = 0.0f, float dy = 0.0f, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+ method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float inset, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+ method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float horizontal = 0.0f, float vertical = 0.0f, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void rotate(androidx.compose.ui.graphics.drawscope.DrawScope, float degrees, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void rotateRad(androidx.compose.ui.graphics.drawscope.DrawScope, float radians, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void scale(androidx.compose.ui.graphics.drawscope.DrawScope, float scaleX, float scaleY = scaleX, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
@@ -911,7 +914,8 @@
}
public final class DrawTransformKt {
- method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float dx = 0.0f, float dy = 0.0f);
+ method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float horizontal = 0.0f, float vertical = 0.0f);
+ method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float inset);
method public static inline void rotateRad(androidx.compose.ui.graphics.drawscope.DrawTransform, float radians, float pivotX = center.x, float pivotY = center.y);
}
diff --git a/compose/ui/ui-graphics/api/public_plus_experimental_current.txt b/compose/ui/ui-graphics/api/public_plus_experimental_current.txt
index 37b8fbe..187547b 100644
--- a/compose/ui/ui-graphics/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-graphics/api/public_plus_experimental_current.txt
@@ -96,7 +96,7 @@
method public void relativeQuadraticBezierTo(float dx1, float dy1, float dx2, float dy2);
method public void reset();
method public void setFillType(androidx.compose.ui.graphics.PathFillType value);
- method public void shift-k-4lQ0M(long offset);
+ method public void translate-k-4lQ0M(long offset);
property public androidx.compose.ui.graphics.PathFillType fillType;
property public boolean isConvex;
property public boolean isEmpty;
@@ -500,7 +500,8 @@
method public void relativeQuadraticBezierTo(float dx1, float dy1, float dx2, float dy2);
method public void reset();
method public void setFillType(androidx.compose.ui.graphics.PathFillType p);
- method public void shift-k-4lQ0M(long offset);
+ method @Deprecated public default void shift-k-4lQ0M(long offset);
+ method public void translate-k-4lQ0M(long offset);
property public abstract androidx.compose.ui.graphics.PathFillType fillType;
property public abstract boolean isConvex;
property public abstract boolean isEmpty;
@@ -880,9 +881,11 @@
public final class DrawScopeKt {
method public static inline void clipPath(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.graphics.Path path, androidx.compose.ui.graphics.ClipOp clipOp = androidx.compose.ui.graphics.ClipOp.Intersect, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void clipRect(androidx.compose.ui.graphics.drawscope.DrawScope, float left = 0.0f, float top = 0.0f, float right = size.width, float bottom = size.height, androidx.compose.ui.graphics.ClipOp clipOp = androidx.compose.ui.graphics.ClipOp.Intersect, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
- method public static inline void drawCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.Canvas,? super androidx.compose.ui.geometry.Size,kotlin.Unit> block);
+ method @Deprecated public static inline void drawCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.Canvas,? super androidx.compose.ui.geometry.Size,kotlin.Unit> block);
+ method public static inline void drawIntoCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.Canvas,kotlin.Unit> block);
method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
- method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float dx = 0.0f, float dy = 0.0f, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+ method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float inset, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+ method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float horizontal = 0.0f, float vertical = 0.0f, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void rotate(androidx.compose.ui.graphics.drawscope.DrawScope, float degrees, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void rotateRad(androidx.compose.ui.graphics.drawscope.DrawScope, float radians, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void scale(androidx.compose.ui.graphics.drawscope.DrawScope, float scaleX, float scaleY = scaleX, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
@@ -911,7 +914,8 @@
}
public final class DrawTransformKt {
- method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float dx = 0.0f, float dy = 0.0f);
+ method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float horizontal = 0.0f, float vertical = 0.0f);
+ method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float inset);
method public static inline void rotateRad(androidx.compose.ui.graphics.drawscope.DrawTransform, float radians, float pivotX = center.x, float pivotY = center.y);
}
diff --git a/compose/ui/ui-graphics/api/restricted_current.txt b/compose/ui/ui-graphics/api/restricted_current.txt
index bf9f72d..4d309aa 100644
--- a/compose/ui/ui-graphics/api/restricted_current.txt
+++ b/compose/ui/ui-graphics/api/restricted_current.txt
@@ -126,7 +126,7 @@
method public void relativeQuadraticBezierTo(float dx1, float dy1, float dx2, float dy2);
method public void reset();
method public void setFillType(androidx.compose.ui.graphics.PathFillType value);
- method public void shift-k-4lQ0M(long offset);
+ method public void translate-k-4lQ0M(long offset);
property public androidx.compose.ui.graphics.PathFillType fillType;
property public boolean isConvex;
property public boolean isEmpty;
@@ -532,7 +532,8 @@
method public void relativeQuadraticBezierTo(float dx1, float dy1, float dx2, float dy2);
method public void reset();
method public void setFillType(androidx.compose.ui.graphics.PathFillType p);
- method public void shift-k-4lQ0M(long offset);
+ method @Deprecated public default void shift-k-4lQ0M(long offset);
+ method public void translate-k-4lQ0M(long offset);
property public abstract androidx.compose.ui.graphics.PathFillType fillType;
property public abstract boolean isConvex;
property public abstract boolean isEmpty;
@@ -915,9 +916,11 @@
public final class DrawScopeKt {
method public static inline void clipPath(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.graphics.Path path, androidx.compose.ui.graphics.ClipOp clipOp = androidx.compose.ui.graphics.ClipOp.Intersect, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void clipRect(androidx.compose.ui.graphics.drawscope.DrawScope, float left = 0.0f, float top = 0.0f, float right = size.width, float bottom = size.height, androidx.compose.ui.graphics.ClipOp clipOp = androidx.compose.ui.graphics.ClipOp.Intersect, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
- method public static inline void drawCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.Canvas,? super androidx.compose.ui.geometry.Size,kotlin.Unit> block);
+ method @Deprecated public static inline void drawCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.Canvas,? super androidx.compose.ui.geometry.Size,kotlin.Unit> block);
+ method public static inline void drawIntoCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.Canvas,kotlin.Unit> block);
method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
- method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float dx = 0.0f, float dy = 0.0f, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+ method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float inset, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+ method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float horizontal = 0.0f, float vertical = 0.0f, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void rotate(androidx.compose.ui.graphics.drawscope.DrawScope, float degrees, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void rotateRad(androidx.compose.ui.graphics.drawscope.DrawScope, float radians, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
method public static inline void scale(androidx.compose.ui.graphics.drawscope.DrawScope, float scaleX, float scaleY = scaleX, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
@@ -946,7 +949,8 @@
}
public final class DrawTransformKt {
- method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float dx = 0.0f, float dy = 0.0f);
+ method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float horizontal = 0.0f, float vertical = 0.0f);
+ method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float inset);
method public static inline void rotateRad(androidx.compose.ui.graphics.drawscope.DrawTransform, float radians, float pivotX = center.x, float pivotY = center.y);
}
diff --git a/compose/ui/ui-graphics/samples/build.gradle b/compose/ui/ui-graphics/samples/build.gradle
index a3603ac..02ccd5b 100644
--- a/compose/ui/ui-graphics/samples/build.gradle
+++ b/compose/ui/ui-graphics/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt b/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt
index 696fafb..fb4cb0e 100644
--- a/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt
+++ b/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt
@@ -271,6 +271,57 @@
}
@Test
+ fun testDrawInsetHorizontalVertical() {
+ val img = createTestDstImage()
+ val insetHorizontal = 10.0f
+ val insetVertical = 12.0f
+ TestDrawScope().drawInto(Canvas(img), dstSize) {
+ inset(insetHorizontal, insetVertical, insetHorizontal, insetVertical) {
+ drawRect(color = Color.Red)
+ }
+ }
+
+ val pixelMap = img.toPixelMap()
+ for (i in 0 until pixelMap.width) {
+ for (j in 0 until pixelMap.height) {
+ val expectedColor =
+ if (i >= insetHorizontal && i < pixelMap.width - insetHorizontal &&
+ j >= insetVertical && j < pixelMap.height - insetVertical) {
+ Color.Red
+ } else {
+ Color.White
+ }
+ assertEquals("Coordinate: " + i + ", " + j, expectedColor, pixelMap[i, j])
+ }
+ }
+ }
+
+ @Test
+ fun testDrawInsetAll() {
+ val img = createTestDstImage()
+ val insetAll = 10.0f
+ TestDrawScope().drawInto(Canvas(img), dstSize) {
+ inset(insetAll) {
+ drawRect(color = Color.Red)
+ }
+ }
+
+ val pixelMap = img.toPixelMap()
+ for (i in 0 until pixelMap.width) {
+ for (j in 0 until pixelMap.height) {
+ val expectedColor =
+ if (i >= insetAll && i < pixelMap.width - insetAll &&
+ j >= insetAll && j < pixelMap.height - insetAll) {
+ Color.Red
+ } else {
+ Color.White
+ }
+ assertEquals("Coordinate: " + i + ", " + j, expectedColor, pixelMap[i, j])
+ }
+ }
+ }
+
+ @Test
fun testInsetRestoredAfterScopedInsetDraw() {
val img = createTestDstImage()
TestDrawScope().drawInto(Canvas(img), dstSize) {
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.kt
index b61bae3..037cdd2 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.kt
@@ -184,7 +184,7 @@
internalPath.reset()
}
- override fun shift(offset: Offset) {
+ override fun translate(offset: Offset) {
mMatrix.reset()
mMatrix.setTranslate(offset.x, offset.y)
internalPath.transform(mMatrix)
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Path.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Path.kt
index 65d1df4..33441dd 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Path.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Path.kt
@@ -231,7 +231,16 @@
/**
* Translates all the segments of every subpath by the given offset.
*/
- fun shift(offset: Offset)
+ @Deprecated(
+ "Use translate(offset) instead",
+ ReplaceWith("translate(offset)", "androidx.compose.ui.graphics.Path")
+ )
+ fun shift(offset: Offset) = translate(offset)
+
+ /**
+ * Translates all the segments of every subpath by the given offset.
+ */
+ fun translate(offset: Offset)
/**
* Compute the bounds of the control points of the path, and write the
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
index fa1465a..94e6658 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
@@ -46,7 +46,8 @@
* the dimensions of the current painting area. This provides a callback to issue more
* drawing instructions within the modified coordinate space. This method
* modifies the width of the [DrawScope] to be equivalent to width - (left + right) as well as
- * height to height - (top + bottom)
+ * height to height - (top + bottom). After this method is invoked, the coordinate space is
+ * returned to the state before the inset was applied.
*
* @param left number of pixels to inset the left drawing bound
* @param top number of pixels to inset the top drawing bound
@@ -67,18 +68,39 @@
}
/**
- * Convenience method modifies the [DrawScope] bounds to inset both left and right bounds by
- * [dx] as well as the top and bottom by [dy]. If only [dx] is provided, the same inset is applied
- * to all 4 bounds
+ * Convenience method modifies the [DrawScope] bounds to inset both left, top, right and
+ * bottom bounds by [inset]. After this method is invoked,
+ * the coordinate space is returned to the state before this inset was applied.
*
- * @param dx number of pixels to inset both left and right bounds
- * @param dy Optional number of pixels to inset both top and bottom bounds, by default this also
- * insets the top and bottom by [dx] pixels
+ * @param inset number of pixels to inset left, top, right, and bottom bounds.
* @param block lambda that is called to issue additional drawing commands within the modified
* coordinate space
*/
-inline fun DrawScope.inset(dx: Float = 0.0f, dy: Float = 0.0f, block: DrawScope.() -> Unit) =
- inset(dx, dy, dx, dy, block)
+inline fun DrawScope.inset(
+ inset: Float,
+ block: DrawScope.() -> Unit
+) {
+ transform.inset(inset, inset, inset, inset)
+ block()
+ transform.inset(-inset, -inset, -inset, -inset)
+}
+
+/**
+ * Convenience method modifies the [DrawScope] bounds to inset both left and right bounds by
+ * [horizontal] as well as the top and bottom by [vertical]. After this method is invoked,
+ * the coordinate space is returned to the state before this inset was applied.
+ *
+ * @param horizontal number of pixels to inset both left and right bounds. Zero by default
+ * @param vertical Optional number of pixels to inset both top and bottom bounds. Zero by
+ * default
+ * @param block lambda that is called to issue additional drawing commands within the modified
+ * coordinate space
+ */
+inline fun DrawScope.inset(
+ horizontal: Float = 0.0f,
+ vertical: Float = 0.0f,
+ block: DrawScope.() -> Unit
+) = inset(horizontal, vertical, horizontal, vertical, block)
/**
* Translate the coordinate space by the given delta in pixels in both the x and y coordinates
@@ -167,14 +189,16 @@
/**
* Reduces the clip region to the intersection of the current clip and the
- * given rectangle indicated by the given left, top, right and bottom bounds.
+ * given rectangle indicated by the given left, top, right and bottom bounds. This provides
+ * a callback to issue drawing commands within the clipped region. After this method is invoked,
+ * this clip is no longer applied.
*
* Use [ClipOp.Difference] to subtract the provided rectangle from the
* current clip.
*
* @param left Left bound of the rectangle to clip
* @param top Top bound of the rectangle to clip
- * @param right Right bound ofthe rectangle to clip
+ * @param right Right bound of the rectangle to clip
* @param bottom Bottom bound of the rectangle to clip
* @param clipOp Clipping operation to conduct on the given bounds, defaults to [ClipOp.Intersect]
* @param block Lambda callback with this CanvasScope as a receiver scope to issue drawing commands
@@ -191,7 +215,8 @@
/**
* Reduces the clip region to the intersection of the current clip and the
- * given rounded rectangle.
+ * given path. This method provides a callback to issue drawing commands within the region
+ * defined by the clipped path. After this method is invoked, this clip is no longer applied.
*
* @param path Shape to clip drawing content within
* @param clipOp Clipping operation to conduct on the given bounds, defaults to [ClipOp.Intersect]
@@ -205,12 +230,27 @@
) = withTransform({ clipPath(path, clipOp) }, block)
/**
+ * Provides access to draw directly with the underlying [Canvas]. This is helpful for situations
+ * to re-use alternative drawing logic in combination with [DrawScope]
+ *
+ * @param block Lambda callback to issue drawing commands on the provided [Canvas]
+ */
+inline fun DrawScope.drawIntoCanvas(block: (Canvas) -> Unit) = block(canvas)
+
+/**
* Provides access to draw directly with the underlying [Canvas] along with the current
* size of the [DrawScope]. This is helpful for situations
* to re-use alternative drawing logic in combination with [DrawScope]
*
* @param block Lambda callback to issue drawing commands on the provided [Canvas] and given size
*/
+@Deprecated(
+ "Use drawIntoCanvas instead",
+ ReplaceWith(
+ "drawIntoCanvas { canvas -> }",
+ "androidx.compose.ui.graphics.drawscope.drawIntoCanvas"
+ )
+)
inline fun DrawScope.drawCanvas(block: (Canvas, Size) -> Unit) = block(canvas, size)
/**
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawTransform.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawTransform.kt
index fc52620..4583266 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawTransform.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawTransform.kt
@@ -25,15 +25,27 @@
/**
* Convenience method modifies the [DrawTransform] bounds to inset both left and right bounds by
- * [dx] as well as the top and bottom by [dy]. If only [dx] is provided, the same inset is applied
- * to all 4 bounds
+ * [horizontal] as well as the top and bottom by [vertical]. After this method is
+ * invoked, the coordinate space is returned to the state before the inset was applied
*
- * @param dx number of pixels to inset both left and right bounds
- * @param dy Optional number of pixels to inset both top and bottom bounds, by default this also
- * insets the top and bottom by [dx] pixels
+ * @param horizontal number of pixels to inset both left and right bounds. Zero by default.
+ * @param vertical number of pixels to inset both top and bottom bounds. Zero by default.
*/
@Suppress("NOTHING_TO_INLINE")
-inline fun DrawTransform.inset(dx: Float = 0.0f, dy: Float = 0.0f) = inset(dx, dy, dx, dy)
+inline fun DrawTransform.inset(horizontal: Float = 0.0f, vertical: Float = 0.0f) =
+ inset(horizontal, vertical, horizontal, vertical)
+
+/**
+ * Convenience method modifies the [DrawScope] bounds to inset both left, top, right and
+ * bottom bounds by [inset]. After this method is invoked,
+ * the coordinate space is returned to the state before this inset was applied.
+ *
+ * @param inset number of pixels to inset left, top, right, and bottom bounds.
+ */
+@Suppress("NOTHING_TO_INLINE")
+inline fun DrawTransform.inset(
+ inset: Float
+) = inset(inset, inset)
/**
* Add a rotation (in radians clockwise) to the current transform at the given pivot point.
@@ -85,7 +97,8 @@
/**
* Reduces the clip region to the intersection of the current clip and the
- * given rectangle indicated by the given left, top, right and bottom bounds
+ * given rectangle indicated by the given left, top, right and bottom bounds.
+ * After this method is invoked, this clip is no longer applied.
*
* Use [ClipOp.Difference] to subtract the provided rectangle from the
* current clip.
@@ -106,7 +119,7 @@
/**
* Reduces the clip region to the intersection of the current clip and the
- * given rounded rectangle.
+ * given rounded rectangle. After this method is invoked, this clip is no longer applied
*
* @param path Shape to clip drawing content within
* @param clipOp Clipping operation to conduct on the given bounds, defaults to [ClipOp.Intersect]
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/painter/Painter.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/painter/Painter.kt
index 4191254..aafa202 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/painter/Painter.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/painter/Painter.kt
@@ -22,7 +22,7 @@
import androidx.compose.ui.graphics.DefaultAlpha
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.drawscope.DrawScope
-import androidx.compose.ui.graphics.drawscope.drawCanvas
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.drawscope.inset
import androidx.compose.ui.graphics.withSaveLayer
import androidx.compose.ui.unit.LayoutDirection
@@ -200,10 +200,9 @@
if (alpha > 0.0f && size.width > 0 && size.height > 0) {
if (useLayer) {
- val layerRect =
- Rect(Offset.Zero, Size(size.width, size.height))
+ val layerRect = Rect(Offset.Zero, Size(size.width, size.height))
// TODO (b/154550724) njawad replace with RenderNode/Layer API usage
- drawCanvas { canvas, _ ->
+ drawIntoCanvas { canvas ->
canvas.withSaveLayer(layerRect, obtainPaint()) {
onDraw()
}
diff --git a/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopPath.kt b/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopPath.kt
index 9c168c8..48c75e7 100644
--- a/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopPath.kt
+++ b/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopPath.kt
@@ -153,7 +153,7 @@
internalPath.reset()
}
- override fun shift(offset: Offset) {
+ override fun translate(offset: Offset) {
internalPath.transform(Matrix33.makeTranslate(offset.x, offset.y))
}
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index dd69004..6fa0ebf 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -72,8 +72,8 @@
}
public final class MultiParagraph {
- ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, int maxLines, boolean ellipsis, androidx.compose.ui.text.ParagraphConstraints constraints);
- ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, int maxLines, boolean ellipsis, androidx.compose.ui.text.ParagraphConstraints constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
+ ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, int maxLines, boolean ellipsis, float width);
+ ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, int maxLines, boolean ellipsis, float width, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
method public androidx.compose.ui.text.style.ResolvedTextDirection getBidiRunDirection(int offset);
method public androidx.compose.ui.geometry.Rect getBoundingBox(int offset);
method public androidx.compose.ui.geometry.Rect getCursorRect(int offset);
@@ -103,7 +103,7 @@
method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
method public float getWidth();
- method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+ method public long getWordBoundary(int offset);
method public boolean isLineEllipsized(int lineIndex);
method public void paint-TAOIQ28(androidx.compose.ui.graphics.Canvas canvas, long color = Color.Unset, androidx.compose.ui.graphics.Shadow? shadow = null, androidx.compose.ui.text.style.TextDecoration? decoration = null);
property public final boolean didExceedMaxLines;
@@ -161,7 +161,7 @@
method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
method public float getWidth();
- method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+ method public long getWordBoundary(int offset);
method public boolean isLineEllipsized(int lineIndex);
method public void paint-TAOIQ28(androidx.compose.ui.graphics.Canvas canvas, long color = Color.Unset, androidx.compose.ui.graphics.Shadow? shadow = null, androidx.compose.ui.text.style.TextDecoration? textDecoration = null);
property public abstract boolean didExceedMaxLines;
@@ -175,13 +175,6 @@
property public abstract float width;
}
- public final class ParagraphConstraints {
- ctor public ParagraphConstraints(float width);
- method public float component1();
- method public androidx.compose.ui.text.ParagraphConstraints copy(float width);
- method public float getWidth();
- }
-
public interface ParagraphIntrinsics {
method public float getMaxIntrinsicWidth();
method public float getMinIntrinsicWidth();
@@ -194,8 +187,8 @@
}
public final class ParagraphKt {
- method public static androidx.compose.ui.text.Paragraph Paragraph(String text, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.SpanStyle>> spanStyles = listOf(), java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders = listOf(), int maxLines = 2147483647, boolean ellipsis = false, androidx.compose.ui.text.ParagraphConstraints constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
- method public static androidx.compose.ui.text.Paragraph Paragraph(androidx.compose.ui.text.ParagraphIntrinsics paragraphIntrinsics, int maxLines = 2147483647, boolean ellipsis = false, androidx.compose.ui.text.ParagraphConstraints constraints);
+ method public static androidx.compose.ui.text.Paragraph Paragraph(String text, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.SpanStyle>> spanStyles = listOf(), java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders = listOf(), int maxLines = 2147483647, boolean ellipsis = false, float width, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
+ method public static androidx.compose.ui.text.Paragraph Paragraph(androidx.compose.ui.text.ParagraphIntrinsics paragraphIntrinsics, int maxLines = 2147483647, boolean ellipsis = false, float width);
}
@androidx.compose.runtime.Immutable public final class ParagraphStyle {
@@ -350,7 +343,7 @@
method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
method public long getSize();
- method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+ method public long getWordBoundary(int offset);
method public boolean isLineEllipsized(int lineIndex);
property public final boolean didOverflowHeight;
property public final boolean didOverflowWidth;
@@ -362,7 +355,7 @@
}
public final class TextLayoutResultKt {
- method @VisibleForTesting public static androidx.compose.ui.text.TextLayoutResult createTextLayoutResult-2H_Vf2E(androidx.compose.ui.text.TextLayoutInput layoutInput = androidx.compose.ui.text.TextLayoutInput(androidx.compose.ui.text.AnnotatedString(""), androidx.compose.ui.text.TextStyle(), emptyList(), 1, false, androidx.compose.ui.text.style.TextOverflow.Clip, Density(1.0), LayoutDirection.Ltr, null(), Constraints()), androidx.compose.ui.text.MultiParagraph multiParagraph = androidx.compose.ui.text.MultiParagraph(text, style, androidx.compose.ui.text.ParagraphConstraints(0.0), density, resourceLoader), long size = IntSize.Zero);
+ method @VisibleForTesting public static androidx.compose.ui.text.TextLayoutResult createTextLayoutResult-2H_Vf2E(androidx.compose.ui.text.TextLayoutInput layoutInput = androidx.compose.ui.text.TextLayoutInput(androidx.compose.ui.text.AnnotatedString(""), androidx.compose.ui.text.TextStyle(), emptyList(), 1, false, androidx.compose.ui.text.style.TextOverflow.Clip, Density(1.0), LayoutDirection.Ltr, null(), Constraints()), androidx.compose.ui.text.MultiParagraph multiParagraph = androidx.compose.ui.text.MultiParagraph(text, style, 0.0, density, resourceLoader), long size = IntSize.Zero);
}
public final class TextPainter {
@@ -370,37 +363,36 @@
field public static final androidx.compose.ui.text.TextPainter INSTANCE;
}
- @androidx.compose.runtime.Immutable public final class TextRange {
- ctor public TextRange(@IntRange(from=0) int start, @IntRange(from=0) int end);
- method public int component1();
- method public int component2();
- method public operator boolean contains(androidx.compose.ui.text.TextRange other);
- method public operator boolean contains(int offset);
- method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.TextRange copy(int start, int end);
- method public boolean getCollapsed();
- method public int getEnd();
- method public int getLength();
- method public int getMax();
- method public int getMin();
- method public boolean getReversed();
- method public int getStart();
- method public boolean intersects(androidx.compose.ui.text.TextRange other);
- property public final boolean collapsed;
- property public final int length;
- property public final int max;
- property public final int min;
- property public final boolean reversed;
+ @androidx.compose.runtime.Immutable public final inline class TextRange {
+ ctor public TextRange();
+ method public static long constructor-impl(long packedValue);
+ method public static long constructor-impl(int start, int end);
+ method public static operator boolean contains-5zc-tL8(long $this, long other);
+ method public static operator boolean contains-impl(long $this, int offset);
+ method @androidx.compose.runtime.Immutable public static inline boolean equals-impl(long p, Object? p1);
+ method public static boolean equals-impl0(long p1, long p2);
+ method public static boolean getCollapsed-impl(long $this);
+ method public static int getEnd-impl(long $this);
+ method public static int getLength-impl(long $this);
+ method public static int getMax-impl(long $this);
+ method public static int getMin-impl(long $this);
+ method public long getPackedValue();
+ method public static boolean getReversed-impl(long $this);
+ method public static int getStart-impl(long $this);
+ method @androidx.compose.runtime.Immutable public static inline int hashCode-impl(long p);
+ method public static boolean intersects-5zc-tL8(long $this, long other);
+ method public static String toString-impl(long $this);
field public static final androidx.compose.ui.text.TextRange.Companion Companion;
}
public static final class TextRange.Companion {
- method public androidx.compose.ui.text.TextRange getZero();
- property public final androidx.compose.ui.text.TextRange Zero;
+ method public long getZero();
+ property public final long Zero;
}
public final class TextRangeKt {
- method public static androidx.compose.ui.text.TextRange TextRange(int index);
- method public static String substring(CharSequence, androidx.compose.ui.text.TextRange range);
+ method public static long TextRange(int index);
+ method public static String substring-cWlJSyE(CharSequence, long range);
}
@androidx.compose.runtime.Immutable public final class TextStyle {
@@ -674,20 +666,17 @@
}
public final class EditingBuffer {
- ctor public EditingBuffer(String initialText, androidx.compose.ui.text.TextRange initialSelection);
field public static final int NOWHERE = -1; // 0xffffffff
}
@Deprecated @androidx.compose.runtime.Immutable public final class EditorValue {
- ctor @Deprecated public EditorValue(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
- ctor @Deprecated public EditorValue();
method @Deprecated public String component1();
- method @Deprecated public androidx.compose.ui.text.TextRange component2();
+ method @Deprecated public long component2();
method @Deprecated public androidx.compose.ui.text.TextRange? component3();
- method @Deprecated @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.EditorValue copy(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
+ method @Deprecated @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.EditorValue copy-Dr2r1M0(String text, long selection, androidx.compose.ui.text.TextRange? composition);
method @Deprecated public androidx.compose.ui.text.TextRange? getComposition();
method @Deprecated public String getSelectedText();
- method @Deprecated public androidx.compose.ui.text.TextRange getSelection();
+ method @Deprecated public long getSelection();
method @Deprecated public String getText();
method @Deprecated public String getTextAfterSelection(int maxChars);
method @Deprecated public String getTextBeforeSelection(int maxChars);
@@ -800,14 +789,12 @@
}
@androidx.compose.runtime.Immutable public final class TextFieldValue {
- ctor public TextFieldValue(@androidx.compose.runtime.Stable String text, @androidx.compose.runtime.Stable androidx.compose.ui.text.TextRange selection, @androidx.compose.runtime.Stable androidx.compose.ui.text.TextRange? composition);
- ctor public TextFieldValue();
method public String component1();
- method public androidx.compose.ui.text.TextRange component2();
+ method public long component2();
method public androidx.compose.ui.text.TextRange? component3();
- method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.TextFieldValue copy(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
+ method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.TextFieldValue copy-Dr2r1M0(String text, long selection, androidx.compose.ui.text.TextRange? composition);
method public androidx.compose.ui.text.TextRange? getComposition();
- method public androidx.compose.ui.text.TextRange getSelection();
+ method public long getSelection();
method public String getText();
field public static final androidx.compose.ui.text.input.TextFieldValue.Companion Companion;
}
diff --git a/compose/ui/ui-text/api/public_plus_experimental_current.txt b/compose/ui/ui-text/api/public_plus_experimental_current.txt
index dd69004..6fa0ebf 100644
--- a/compose/ui/ui-text/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-text/api/public_plus_experimental_current.txt
@@ -72,8 +72,8 @@
}
public final class MultiParagraph {
- ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, int maxLines, boolean ellipsis, androidx.compose.ui.text.ParagraphConstraints constraints);
- ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, int maxLines, boolean ellipsis, androidx.compose.ui.text.ParagraphConstraints constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
+ ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, int maxLines, boolean ellipsis, float width);
+ ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, int maxLines, boolean ellipsis, float width, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
method public androidx.compose.ui.text.style.ResolvedTextDirection getBidiRunDirection(int offset);
method public androidx.compose.ui.geometry.Rect getBoundingBox(int offset);
method public androidx.compose.ui.geometry.Rect getCursorRect(int offset);
@@ -103,7 +103,7 @@
method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
method public float getWidth();
- method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+ method public long getWordBoundary(int offset);
method public boolean isLineEllipsized(int lineIndex);
method public void paint-TAOIQ28(androidx.compose.ui.graphics.Canvas canvas, long color = Color.Unset, androidx.compose.ui.graphics.Shadow? shadow = null, androidx.compose.ui.text.style.TextDecoration? decoration = null);
property public final boolean didExceedMaxLines;
@@ -161,7 +161,7 @@
method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
method public float getWidth();
- method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+ method public long getWordBoundary(int offset);
method public boolean isLineEllipsized(int lineIndex);
method public void paint-TAOIQ28(androidx.compose.ui.graphics.Canvas canvas, long color = Color.Unset, androidx.compose.ui.graphics.Shadow? shadow = null, androidx.compose.ui.text.style.TextDecoration? textDecoration = null);
property public abstract boolean didExceedMaxLines;
@@ -175,13 +175,6 @@
property public abstract float width;
}
- public final class ParagraphConstraints {
- ctor public ParagraphConstraints(float width);
- method public float component1();
- method public androidx.compose.ui.text.ParagraphConstraints copy(float width);
- method public float getWidth();
- }
-
public interface ParagraphIntrinsics {
method public float getMaxIntrinsicWidth();
method public float getMinIntrinsicWidth();
@@ -194,8 +187,8 @@
}
public final class ParagraphKt {
- method public static androidx.compose.ui.text.Paragraph Paragraph(String text, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.SpanStyle>> spanStyles = listOf(), java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders = listOf(), int maxLines = 2147483647, boolean ellipsis = false, androidx.compose.ui.text.ParagraphConstraints constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
- method public static androidx.compose.ui.text.Paragraph Paragraph(androidx.compose.ui.text.ParagraphIntrinsics paragraphIntrinsics, int maxLines = 2147483647, boolean ellipsis = false, androidx.compose.ui.text.ParagraphConstraints constraints);
+ method public static androidx.compose.ui.text.Paragraph Paragraph(String text, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.SpanStyle>> spanStyles = listOf(), java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders = listOf(), int maxLines = 2147483647, boolean ellipsis = false, float width, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
+ method public static androidx.compose.ui.text.Paragraph Paragraph(androidx.compose.ui.text.ParagraphIntrinsics paragraphIntrinsics, int maxLines = 2147483647, boolean ellipsis = false, float width);
}
@androidx.compose.runtime.Immutable public final class ParagraphStyle {
@@ -350,7 +343,7 @@
method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
method public long getSize();
- method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+ method public long getWordBoundary(int offset);
method public boolean isLineEllipsized(int lineIndex);
property public final boolean didOverflowHeight;
property public final boolean didOverflowWidth;
@@ -362,7 +355,7 @@
}
public final class TextLayoutResultKt {
- method @VisibleForTesting public static androidx.compose.ui.text.TextLayoutResult createTextLayoutResult-2H_Vf2E(androidx.compose.ui.text.TextLayoutInput layoutInput = androidx.compose.ui.text.TextLayoutInput(androidx.compose.ui.text.AnnotatedString(""), androidx.compose.ui.text.TextStyle(), emptyList(), 1, false, androidx.compose.ui.text.style.TextOverflow.Clip, Density(1.0), LayoutDirection.Ltr, null(), Constraints()), androidx.compose.ui.text.MultiParagraph multiParagraph = androidx.compose.ui.text.MultiParagraph(text, style, androidx.compose.ui.text.ParagraphConstraints(0.0), density, resourceLoader), long size = IntSize.Zero);
+ method @VisibleForTesting public static androidx.compose.ui.text.TextLayoutResult createTextLayoutResult-2H_Vf2E(androidx.compose.ui.text.TextLayoutInput layoutInput = androidx.compose.ui.text.TextLayoutInput(androidx.compose.ui.text.AnnotatedString(""), androidx.compose.ui.text.TextStyle(), emptyList(), 1, false, androidx.compose.ui.text.style.TextOverflow.Clip, Density(1.0), LayoutDirection.Ltr, null(), Constraints()), androidx.compose.ui.text.MultiParagraph multiParagraph = androidx.compose.ui.text.MultiParagraph(text, style, 0.0, density, resourceLoader), long size = IntSize.Zero);
}
public final class TextPainter {
@@ -370,37 +363,36 @@
field public static final androidx.compose.ui.text.TextPainter INSTANCE;
}
- @androidx.compose.runtime.Immutable public final class TextRange {
- ctor public TextRange(@IntRange(from=0) int start, @IntRange(from=0) int end);
- method public int component1();
- method public int component2();
- method public operator boolean contains(androidx.compose.ui.text.TextRange other);
- method public operator boolean contains(int offset);
- method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.TextRange copy(int start, int end);
- method public boolean getCollapsed();
- method public int getEnd();
- method public int getLength();
- method public int getMax();
- method public int getMin();
- method public boolean getReversed();
- method public int getStart();
- method public boolean intersects(androidx.compose.ui.text.TextRange other);
- property public final boolean collapsed;
- property public final int length;
- property public final int max;
- property public final int min;
- property public final boolean reversed;
+ @androidx.compose.runtime.Immutable public final inline class TextRange {
+ ctor public TextRange();
+ method public static long constructor-impl(long packedValue);
+ method public static long constructor-impl(int start, int end);
+ method public static operator boolean contains-5zc-tL8(long $this, long other);
+ method public static operator boolean contains-impl(long $this, int offset);
+ method @androidx.compose.runtime.Immutable public static inline boolean equals-impl(long p, Object? p1);
+ method public static boolean equals-impl0(long p1, long p2);
+ method public static boolean getCollapsed-impl(long $this);
+ method public static int getEnd-impl(long $this);
+ method public static int getLength-impl(long $this);
+ method public static int getMax-impl(long $this);
+ method public static int getMin-impl(long $this);
+ method public long getPackedValue();
+ method public static boolean getReversed-impl(long $this);
+ method public static int getStart-impl(long $this);
+ method @androidx.compose.runtime.Immutable public static inline int hashCode-impl(long p);
+ method public static boolean intersects-5zc-tL8(long $this, long other);
+ method public static String toString-impl(long $this);
field public static final androidx.compose.ui.text.TextRange.Companion Companion;
}
public static final class TextRange.Companion {
- method public androidx.compose.ui.text.TextRange getZero();
- property public final androidx.compose.ui.text.TextRange Zero;
+ method public long getZero();
+ property public final long Zero;
}
public final class TextRangeKt {
- method public static androidx.compose.ui.text.TextRange TextRange(int index);
- method public static String substring(CharSequence, androidx.compose.ui.text.TextRange range);
+ method public static long TextRange(int index);
+ method public static String substring-cWlJSyE(CharSequence, long range);
}
@androidx.compose.runtime.Immutable public final class TextStyle {
@@ -674,20 +666,17 @@
}
public final class EditingBuffer {
- ctor public EditingBuffer(String initialText, androidx.compose.ui.text.TextRange initialSelection);
field public static final int NOWHERE = -1; // 0xffffffff
}
@Deprecated @androidx.compose.runtime.Immutable public final class EditorValue {
- ctor @Deprecated public EditorValue(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
- ctor @Deprecated public EditorValue();
method @Deprecated public String component1();
- method @Deprecated public androidx.compose.ui.text.TextRange component2();
+ method @Deprecated public long component2();
method @Deprecated public androidx.compose.ui.text.TextRange? component3();
- method @Deprecated @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.EditorValue copy(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
+ method @Deprecated @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.EditorValue copy-Dr2r1M0(String text, long selection, androidx.compose.ui.text.TextRange? composition);
method @Deprecated public androidx.compose.ui.text.TextRange? getComposition();
method @Deprecated public String getSelectedText();
- method @Deprecated public androidx.compose.ui.text.TextRange getSelection();
+ method @Deprecated public long getSelection();
method @Deprecated public String getText();
method @Deprecated public String getTextAfterSelection(int maxChars);
method @Deprecated public String getTextBeforeSelection(int maxChars);
@@ -800,14 +789,12 @@
}
@androidx.compose.runtime.Immutable public final class TextFieldValue {
- ctor public TextFieldValue(@androidx.compose.runtime.Stable String text, @androidx.compose.runtime.Stable androidx.compose.ui.text.TextRange selection, @androidx.compose.runtime.Stable androidx.compose.ui.text.TextRange? composition);
- ctor public TextFieldValue();
method public String component1();
- method public androidx.compose.ui.text.TextRange component2();
+ method public long component2();
method public androidx.compose.ui.text.TextRange? component3();
- method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.TextFieldValue copy(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
+ method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.TextFieldValue copy-Dr2r1M0(String text, long selection, androidx.compose.ui.text.TextRange? composition);
method public androidx.compose.ui.text.TextRange? getComposition();
- method public androidx.compose.ui.text.TextRange getSelection();
+ method public long getSelection();
method public String getText();
field public static final androidx.compose.ui.text.input.TextFieldValue.Companion Companion;
}
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index dd69004..6fa0ebf 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -72,8 +72,8 @@
}
public final class MultiParagraph {
- ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, int maxLines, boolean ellipsis, androidx.compose.ui.text.ParagraphConstraints constraints);
- ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, int maxLines, boolean ellipsis, androidx.compose.ui.text.ParagraphConstraints constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
+ ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, int maxLines, boolean ellipsis, float width);
+ ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, int maxLines, boolean ellipsis, float width, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
method public androidx.compose.ui.text.style.ResolvedTextDirection getBidiRunDirection(int offset);
method public androidx.compose.ui.geometry.Rect getBoundingBox(int offset);
method public androidx.compose.ui.geometry.Rect getCursorRect(int offset);
@@ -103,7 +103,7 @@
method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
method public float getWidth();
- method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+ method public long getWordBoundary(int offset);
method public boolean isLineEllipsized(int lineIndex);
method public void paint-TAOIQ28(androidx.compose.ui.graphics.Canvas canvas, long color = Color.Unset, androidx.compose.ui.graphics.Shadow? shadow = null, androidx.compose.ui.text.style.TextDecoration? decoration = null);
property public final boolean didExceedMaxLines;
@@ -161,7 +161,7 @@
method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
method public float getWidth();
- method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+ method public long getWordBoundary(int offset);
method public boolean isLineEllipsized(int lineIndex);
method public void paint-TAOIQ28(androidx.compose.ui.graphics.Canvas canvas, long color = Color.Unset, androidx.compose.ui.graphics.Shadow? shadow = null, androidx.compose.ui.text.style.TextDecoration? textDecoration = null);
property public abstract boolean didExceedMaxLines;
@@ -175,13 +175,6 @@
property public abstract float width;
}
- public final class ParagraphConstraints {
- ctor public ParagraphConstraints(float width);
- method public float component1();
- method public androidx.compose.ui.text.ParagraphConstraints copy(float width);
- method public float getWidth();
- }
-
public interface ParagraphIntrinsics {
method public float getMaxIntrinsicWidth();
method public float getMinIntrinsicWidth();
@@ -194,8 +187,8 @@
}
public final class ParagraphKt {
- method public static androidx.compose.ui.text.Paragraph Paragraph(String text, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.SpanStyle>> spanStyles = listOf(), java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders = listOf(), int maxLines = 2147483647, boolean ellipsis = false, androidx.compose.ui.text.ParagraphConstraints constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
- method public static androidx.compose.ui.text.Paragraph Paragraph(androidx.compose.ui.text.ParagraphIntrinsics paragraphIntrinsics, int maxLines = 2147483647, boolean ellipsis = false, androidx.compose.ui.text.ParagraphConstraints constraints);
+ method public static androidx.compose.ui.text.Paragraph Paragraph(String text, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.SpanStyle>> spanStyles = listOf(), java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders = listOf(), int maxLines = 2147483647, boolean ellipsis = false, float width, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
+ method public static androidx.compose.ui.text.Paragraph Paragraph(androidx.compose.ui.text.ParagraphIntrinsics paragraphIntrinsics, int maxLines = 2147483647, boolean ellipsis = false, float width);
}
@androidx.compose.runtime.Immutable public final class ParagraphStyle {
@@ -350,7 +343,7 @@
method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
method public long getSize();
- method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+ method public long getWordBoundary(int offset);
method public boolean isLineEllipsized(int lineIndex);
property public final boolean didOverflowHeight;
property public final boolean didOverflowWidth;
@@ -362,7 +355,7 @@
}
public final class TextLayoutResultKt {
- method @VisibleForTesting public static androidx.compose.ui.text.TextLayoutResult createTextLayoutResult-2H_Vf2E(androidx.compose.ui.text.TextLayoutInput layoutInput = androidx.compose.ui.text.TextLayoutInput(androidx.compose.ui.text.AnnotatedString(""), androidx.compose.ui.text.TextStyle(), emptyList(), 1, false, androidx.compose.ui.text.style.TextOverflow.Clip, Density(1.0), LayoutDirection.Ltr, null(), Constraints()), androidx.compose.ui.text.MultiParagraph multiParagraph = androidx.compose.ui.text.MultiParagraph(text, style, androidx.compose.ui.text.ParagraphConstraints(0.0), density, resourceLoader), long size = IntSize.Zero);
+ method @VisibleForTesting public static androidx.compose.ui.text.TextLayoutResult createTextLayoutResult-2H_Vf2E(androidx.compose.ui.text.TextLayoutInput layoutInput = androidx.compose.ui.text.TextLayoutInput(androidx.compose.ui.text.AnnotatedString(""), androidx.compose.ui.text.TextStyle(), emptyList(), 1, false, androidx.compose.ui.text.style.TextOverflow.Clip, Density(1.0), LayoutDirection.Ltr, null(), Constraints()), androidx.compose.ui.text.MultiParagraph multiParagraph = androidx.compose.ui.text.MultiParagraph(text, style, 0.0, density, resourceLoader), long size = IntSize.Zero);
}
public final class TextPainter {
@@ -370,37 +363,36 @@
field public static final androidx.compose.ui.text.TextPainter INSTANCE;
}
- @androidx.compose.runtime.Immutable public final class TextRange {
- ctor public TextRange(@IntRange(from=0) int start, @IntRange(from=0) int end);
- method public int component1();
- method public int component2();
- method public operator boolean contains(androidx.compose.ui.text.TextRange other);
- method public operator boolean contains(int offset);
- method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.TextRange copy(int start, int end);
- method public boolean getCollapsed();
- method public int getEnd();
- method public int getLength();
- method public int getMax();
- method public int getMin();
- method public boolean getReversed();
- method public int getStart();
- method public boolean intersects(androidx.compose.ui.text.TextRange other);
- property public final boolean collapsed;
- property public final int length;
- property public final int max;
- property public final int min;
- property public final boolean reversed;
+ @androidx.compose.runtime.Immutable public final inline class TextRange {
+ ctor public TextRange();
+ method public static long constructor-impl(long packedValue);
+ method public static long constructor-impl(int start, int end);
+ method public static operator boolean contains-5zc-tL8(long $this, long other);
+ method public static operator boolean contains-impl(long $this, int offset);
+ method @androidx.compose.runtime.Immutable public static inline boolean equals-impl(long p, Object? p1);
+ method public static boolean equals-impl0(long p1, long p2);
+ method public static boolean getCollapsed-impl(long $this);
+ method public static int getEnd-impl(long $this);
+ method public static int getLength-impl(long $this);
+ method public static int getMax-impl(long $this);
+ method public static int getMin-impl(long $this);
+ method public long getPackedValue();
+ method public static boolean getReversed-impl(long $this);
+ method public static int getStart-impl(long $this);
+ method @androidx.compose.runtime.Immutable public static inline int hashCode-impl(long p);
+ method public static boolean intersects-5zc-tL8(long $this, long other);
+ method public static String toString-impl(long $this);
field public static final androidx.compose.ui.text.TextRange.Companion Companion;
}
public static final class TextRange.Companion {
- method public androidx.compose.ui.text.TextRange getZero();
- property public final androidx.compose.ui.text.TextRange Zero;
+ method public long getZero();
+ property public final long Zero;
}
public final class TextRangeKt {
- method public static androidx.compose.ui.text.TextRange TextRange(int index);
- method public static String substring(CharSequence, androidx.compose.ui.text.TextRange range);
+ method public static long TextRange(int index);
+ method public static String substring-cWlJSyE(CharSequence, long range);
}
@androidx.compose.runtime.Immutable public final class TextStyle {
@@ -674,20 +666,17 @@
}
public final class EditingBuffer {
- ctor public EditingBuffer(String initialText, androidx.compose.ui.text.TextRange initialSelection);
field public static final int NOWHERE = -1; // 0xffffffff
}
@Deprecated @androidx.compose.runtime.Immutable public final class EditorValue {
- ctor @Deprecated public EditorValue(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
- ctor @Deprecated public EditorValue();
method @Deprecated public String component1();
- method @Deprecated public androidx.compose.ui.text.TextRange component2();
+ method @Deprecated public long component2();
method @Deprecated public androidx.compose.ui.text.TextRange? component3();
- method @Deprecated @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.EditorValue copy(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
+ method @Deprecated @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.EditorValue copy-Dr2r1M0(String text, long selection, androidx.compose.ui.text.TextRange? composition);
method @Deprecated public androidx.compose.ui.text.TextRange? getComposition();
method @Deprecated public String getSelectedText();
- method @Deprecated public androidx.compose.ui.text.TextRange getSelection();
+ method @Deprecated public long getSelection();
method @Deprecated public String getText();
method @Deprecated public String getTextAfterSelection(int maxChars);
method @Deprecated public String getTextBeforeSelection(int maxChars);
@@ -800,14 +789,12 @@
}
@androidx.compose.runtime.Immutable public final class TextFieldValue {
- ctor public TextFieldValue(@androidx.compose.runtime.Stable String text, @androidx.compose.runtime.Stable androidx.compose.ui.text.TextRange selection, @androidx.compose.runtime.Stable androidx.compose.ui.text.TextRange? composition);
- ctor public TextFieldValue();
method public String component1();
- method public androidx.compose.ui.text.TextRange component2();
+ method public long component2();
method public androidx.compose.ui.text.TextRange? component3();
- method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.TextFieldValue copy(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
+ method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.TextFieldValue copy-Dr2r1M0(String text, long selection, androidx.compose.ui.text.TextRange? composition);
method public androidx.compose.ui.text.TextRange? getComposition();
- method public androidx.compose.ui.text.TextRange getSelection();
+ method public long getSelection();
method public String getText();
field public static final androidx.compose.ui.text.input.TextFieldValue.Companion Companion;
}
diff --git a/compose/ui/ui-text/samples/build.gradle b/compose/ui/ui-text/samples/build.gradle
index 913904e..e213e45 100644
--- a/compose/ui/ui-text/samples/build.gradle
+++ b/compose/ui/ui-text/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt
index 1abd85c..87135d0 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt
@@ -1231,7 +1231,7 @@
val paragraph = MultiParagraph(
annotatedString = text,
style = TextStyle(textDirection = TextDirection.Rtl),
- constraints = ParagraphConstraints(Float.MAX_VALUE),
+ width = Float.MAX_VALUE,
density = defaultDensity,
resourceLoader = TestFontResourceLoader(context)
)
@@ -1263,7 +1263,7 @@
fontFamily = fontFamilyMeasureFont
),
placeholders = placeholders,
- constraints = ParagraphConstraints(Float.MAX_VALUE),
+ width = Float.MAX_VALUE,
density = defaultDensity,
resourceLoader = TestFontResourceLoader(context)
)
@@ -1294,7 +1294,7 @@
fontFamily = fontFamilyMeasureFont
),
placeholders = placeholders,
- constraints = ParagraphConstraints(Float.MAX_VALUE),
+ width = Float.MAX_VALUE,
density = defaultDensity,
resourceLoader = TestFontResourceLoader(context)
)
@@ -1326,7 +1326,7 @@
fontFamily = fontFamilyMeasureFont
),
placeholders = placeholders,
- constraints = ParagraphConstraints(Float.MAX_VALUE),
+ width = Float.MAX_VALUE,
density = defaultDensity,
resourceLoader = TestFontResourceLoader(context)
)
@@ -1368,7 +1368,7 @@
fontFamily = fontFamilyMeasureFont
),
placeholders = placeholders,
- constraints = ParagraphConstraints(Float.MAX_VALUE),
+ width = Float.MAX_VALUE,
density = defaultDensity,
resourceLoader = TestFontResourceLoader(context)
)
@@ -1413,7 +1413,7 @@
fontFamily = fontFamilyMeasureFont
),
placeholders = placeholders,
- constraints = ParagraphConstraints(Float.MAX_VALUE),
+ width = Float.MAX_VALUE,
density = defaultDensity,
resourceLoader = TestFontResourceLoader(context)
)
@@ -1469,7 +1469,7 @@
fontSize = fontSize
).merge(style),
maxLines = maxLines,
- constraints = ParagraphConstraints(width),
+ width = width,
density = defaultDensity,
resourceLoader = TestFontResourceLoader(context)
)
@@ -1491,7 +1491,7 @@
localeList = localeList
).merge(style),
maxLines = maxLines,
- constraints = ParagraphConstraints(width),
+ width = width,
density = defaultDensity,
resourceLoader = TestFontResourceLoader(context)
)
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTextDirectionTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTextDirectionTest.kt
index 74d0bc0..13fea3a 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTextDirectionTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTextDirectionTest.kt
@@ -283,7 +283,7 @@
localeList = localeList,
textDirection = textDirection
),
- constraints = ParagraphConstraints(width),
+ width = width,
density = defaultDensity,
resourceLoader = TestFontResourceLoader(context)
)
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt
index 4d2484b..8ea1e59 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt
@@ -74,7 +74,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.width).isEqualTo(100.0f)
@@ -99,7 +99,7 @@
text = text,
style = TextStyle(fontSize = fontSize),
// width greater than text width - 150
- constraints = ParagraphConstraints(width = 200.0f)
+ width = 200.0f
)
assertWithMessage(text).that(paragraph.width).isEqualTo(200.0f)
@@ -126,7 +126,7 @@
text = text,
style = TextStyle(fontSize = fontSize),
// 3 chars width
- constraints = ParagraphConstraints(width = 3 * fontSizeInPx)
+ width = 3 * fontSizeInPx
)
// 3 chars
@@ -159,7 +159,7 @@
text = text,
style = TextStyle(fontSize = fontSize),
// 3 chars width
- constraints = ParagraphConstraints(width = 3 * fontSizeInPx)
+ width = 3 * fontSizeInPx
)
// 3 chars
@@ -190,7 +190,7 @@
text = text,
style = TextStyle(fontSize = fontSize),
// 2 chars width
- constraints = ParagraphConstraints(width = 2 * fontSizeInPx)
+ width = 2 * fontSizeInPx
)
// 2 chars
@@ -220,7 +220,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
// test positions that are 1, fontSize+1, 2fontSize+1 which maps to chars 0, 1, 2 ...
@@ -242,7 +242,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
// test positions that are 1, fontSize+1, 2fontSize+1 which maps to chars .., 2, 1, 0
@@ -266,7 +266,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = firstLine.length * fontSizeInPx)
+ width = firstLine.length * fontSizeInPx
)
// test positions are 1, fontSize+1, 2fontSize+1 and always on the second line
@@ -292,7 +292,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = firstLine.length * fontSizeInPx)
+ width = firstLine.length * fontSizeInPx
)
// test positions are 1, fontSize+1, 2fontSize+1 and always on the second line
@@ -316,7 +316,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
// greater than width
@@ -340,7 +340,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
// greater than height
@@ -370,7 +370,7 @@
fontSize = fontSize.sp,
lineHeight = lineHeight.sp
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
assertThat(paragraph.lineCount).isEqualTo(4)
@@ -401,7 +401,7 @@
fontSize = fontSize.sp,
lineHeight = lineHeight.sp
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
assertThat(paragraph.lineCount).isEqualTo(4)
@@ -432,7 +432,7 @@
fontSize = fontSize.sp,
lineHeight = lineHeight.sp
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
assertThat(paragraph.lineCount).isEqualTo(4)
@@ -457,7 +457,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
// test positions that are 0, 1, 2 ... which maps to chars 0, 1, 2 ...
@@ -482,7 +482,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = firstLine.length * fontSizeInPx)
+ width = firstLine.length * fontSizeInPx
)
// test positions are 3, 4, 5 and always on the second line
@@ -507,7 +507,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
val textPosition = -1
@@ -529,7 +529,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
val textPosition = text.length + 1
@@ -546,7 +546,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
paragraph.getCursorRect(text.length + 1)
@@ -562,7 +562,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
paragraph.getCursorRect(-1)
@@ -578,7 +578,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
for (i in text.indices) {
@@ -606,7 +606,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = charsPerLine * fontSizeInPx)
+ width = charsPerLine * fontSizeInPx
)
for (i in 0 until charsPerLine) {
@@ -710,7 +710,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
for (i in text.indices) {
@@ -737,7 +737,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = charsPerLine * fontSizeInPx)
+ width = charsPerLine * fontSizeInPx
)
for (i in 0 until charsPerLine) {
@@ -775,7 +775,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = 3 * fontSizeInPx)
+ width = 3 * fontSizeInPx
)
// Cursor before '\n'
@@ -810,7 +810,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize, localeList = ltrLocaleList),
- constraints = ParagraphConstraints(width = 3 * fontSizeInPx)
+ width = 3 * fontSizeInPx
)
// Cursor before '\n'
@@ -844,7 +844,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
for (i in 0..text.length) {
@@ -864,7 +864,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0..text.length) {
@@ -886,7 +886,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0..ltrText.length) {
@@ -917,7 +917,7 @@
fontSize = fontSize,
textDirection = TextDirection.Rtl
),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(0, true)).isEqualTo(width)
@@ -944,7 +944,7 @@
fontSize = fontSize,
textDirection = TextDirection.Ltr
),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(0, true)).isZero()
@@ -974,7 +974,7 @@
fontSize = fontSize,
textDirection = TextDirection.Ltr
),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0..ltrText.length) {
@@ -1007,7 +1007,7 @@
fontSize = fontSize,
textDirection = TextDirection.Rtl
),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(0, true)).isEqualTo(width)
@@ -1034,7 +1034,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize, localeList = ltrLocaleList),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(text.length, true)).isZero()
@@ -1053,7 +1053,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize, localeList = ltrLocaleList),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(text.length, true)).isZero()
@@ -1073,7 +1073,7 @@
fontSize = fontSize,
textDirection = TextDirection.Rtl
),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(text.length, true))
@@ -1094,7 +1094,7 @@
fontSize = fontSize,
textDirection = TextDirection.Ltr
),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(text.length, true)).isZero()
@@ -1110,7 +1110,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+ width = text.length * fontSizeInPx
)
for (i in 0..text.length) {
@@ -1130,7 +1130,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0..text.length) {
@@ -1152,7 +1152,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in ltrText.indices) {
@@ -1180,7 +1180,7 @@
fontSize = fontSize,
textDirection = TextDirection.Rtl
),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(0, false)).isZero()
@@ -1208,7 +1208,7 @@
fontSize = fontSize,
textDirection = TextDirection.Ltr
),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(0, false)).isEqualTo(width)
@@ -1237,7 +1237,7 @@
fontSize = fontSize,
textDirection = TextDirection.Ltr
),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in ltrText.indices) {
@@ -1270,7 +1270,7 @@
fontSize = fontSize,
textDirection = TextDirection.Rtl
),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(0, false))
@@ -1298,7 +1298,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize, localeList = ltrLocaleList),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(text.length, false)).isZero()
@@ -1317,7 +1317,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize, localeList = ltrLocaleList),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(text.length, false)).isZero()
@@ -1337,7 +1337,7 @@
fontSize = fontSize,
textDirection = TextDirection.Rtl
),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(text.length, false))
@@ -1358,7 +1358,7 @@
fontSize = fontSize,
textDirection = TextDirection.Ltr
),
- constraints = ParagraphConstraints(width)
+ width = width
)
assertThat(paragraph.getHorizontalPosition(text.length, false)).isZero()
@@ -1375,7 +1375,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0..text.length) {
@@ -1397,7 +1397,7 @@
fontSize = fontSize,
textDirection = TextDirection.Rtl
),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0..text.length) {
@@ -1416,7 +1416,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in text.indices) {
@@ -1438,7 +1438,7 @@
fontSize = fontSize,
textDirection = TextDirection.Ltr
),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0..text.length) {
@@ -1459,7 +1459,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0..text.length) {
@@ -1483,7 +1483,7 @@
fontSize = fontSize,
textDirection = TextDirection.Ltr
),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0..text.length) {
@@ -1507,7 +1507,7 @@
fontSize = fontSize,
textDirection = TextDirection.Rtl
),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0..text.length) {
@@ -1526,7 +1526,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0..text.length) {
@@ -1548,7 +1548,7 @@
fontSize = fontSize,
textDirection = TextDirection.Rtl
),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0..text.length) {
@@ -1567,7 +1567,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in text.indices) {
@@ -1589,7 +1589,7 @@
fontSize = fontSize,
textDirection = TextDirection.Ltr
),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in 0 until text.length - 1) {
@@ -1613,7 +1613,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in ltrText.indices) {
@@ -1641,7 +1641,7 @@
fontSize = fontSize,
textDirection = TextDirection.Ltr
),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in ltrText.indices) {
@@ -1669,7 +1669,7 @@
fontSize = fontSize,
textDirection = TextDirection.Rtl
),
- constraints = ParagraphConstraints(width)
+ width = width
)
for (i in ltrText.indices) {
@@ -1707,7 +1707,7 @@
density = defaultDensity,
resourceLoader = resourceLoader,
// just have 10x font size to have a bitmap
- constraints = ParagraphConstraints(width = fontSizeInPx * 10)
+ width = fontSizeInPx * 10
)
paragraph.bitmap()
@@ -1842,7 +1842,7 @@
text = text,
style = TextStyle(fontSize = fontSize),
maxLines = maxLines,
- constraints = ParagraphConstraints(width = 200f)
+ width = 200f
)
val expectHeight = (lineCount + (lineCount - 1) * 0.2f) * fontSizeInPx
@@ -1862,13 +1862,13 @@
text = text,
style = TextStyle(fontSize = fontSize),
maxLines = maxLines,
- constraints = ParagraphConstraints(width = fontSizeInPx)
+ width = fontSizeInPx
)
val paragraphNoMaxLine = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = fontSizeInPx)
+ width = fontSizeInPx
)
// Make sure the maxLine is applied correctly
@@ -1941,7 +1941,7 @@
style = TextStyle(fontSize = fontSize),
maxLines = maxLines,
// One line can only contain 1 character
- constraints = ParagraphConstraints(width = fontSizeInPx)
+ width = fontSizeInPx
)
assertThat(paragraph.didExceedMaxLines).isTrue()
@@ -1972,7 +1972,7 @@
style = TextStyle(fontSize = fontSize),
maxLines = maxLines,
// One line can only contain 1 character
- constraints = ParagraphConstraints(width = fontSizeInPx)
+ width = fontSizeInPx
)
assertThat(paragraph.didExceedMaxLines).isFalse()
@@ -2031,7 +2031,7 @@
maxLines = maxLines,
ellipsis = true,
// One line can only contain 1 character
- constraints = ParagraphConstraints(width = fontSizeInPx)
+ width = fontSizeInPx
)
assertThat(paragraph.didExceedMaxLines).isTrue()
@@ -2064,7 +2064,7 @@
maxLines = maxLines,
ellipsis = true,
// One line can only contain 1 character
- constraints = ParagraphConstraints(width = fontSizeInPx)
+ width = fontSizeInPx
)
assertThat(paragraph.didExceedMaxLines).isFalse()
@@ -2083,14 +2083,14 @@
val paragraphLTR = simpleParagraph(
text = textLTR,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = layoutLTRWidth)
+ width = layoutLTRWidth
)
val layoutRTLWidth = (textRTL.length + 2) * fontSizeInPx
val paragraphRTL = simpleParagraph(
text = textRTL,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = layoutRTLWidth)
+ width = layoutRTLWidth
)
// When textAlign is TextAlign.start, LTR aligns to left, RTL aligns to right.
@@ -2114,7 +2114,7 @@
fontSize = fontSize,
textAlign = TextAlign.Left
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
assertThat(paragraph.getLineLeft(0)).isZero()
@@ -2138,7 +2138,7 @@
textAlign = TextAlign.Right
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
assertThat(paragraph.getLineRight(0)).isEqualTo(layoutWidth)
@@ -2161,7 +2161,7 @@
fontSize = fontSize,
textAlign = TextAlign.Center
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
val textWidth = text.length * fontSizeInPx
@@ -2185,7 +2185,7 @@
fontSize = fontSize,
textAlign = TextAlign.Start
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
assertThat(paragraph.getLineLeft(0)).isZero()
@@ -2206,7 +2206,7 @@
fontSize = fontSize,
textAlign = TextAlign.End
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
assertThat(paragraph.getLineRight(0)).isEqualTo(layoutWidth)
@@ -2227,7 +2227,7 @@
fontSize = fontSize,
textAlign = TextAlign.Start
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
assertThat(paragraph.getLineRight(0)).isEqualTo(layoutWidth)
@@ -2249,7 +2249,7 @@
fontSize = fontSize,
textAlign = TextAlign.End
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
assertThat(paragraph.getLineLeft(0)).isZero()
@@ -2273,7 +2273,7 @@
fontSize = fontSize,
textAlign = TextAlign.Justify
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
assertThat(paragraph.getLineLeft(0)).isZero()
@@ -2297,7 +2297,7 @@
fontSize = fontSize,
textDirection = TextDirection.Ltr
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
// The position of the last character in display order.
@@ -2321,7 +2321,7 @@
fontSize = fontSize,
textDirection = TextDirection.Rtl
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
// The position of the first character in display order.
@@ -2342,7 +2342,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize, localeList = ltrLocaleList),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
for (i in 0..text.length) {
@@ -2365,7 +2365,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
for (i in text.indices) {
@@ -2388,7 +2388,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
// The first character in display order should be '.'
@@ -2438,7 +2438,7 @@
val paragraph = simpleParagraph(
text = text,
- constraints = ParagraphConstraints(Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
for (i in 0..2) {
assertThat(paragraph.getLineForOffset(i)).isEqualTo(0)
@@ -2454,7 +2454,7 @@
val paragraph = simpleParagraph(
text = text,
- constraints = ParagraphConstraints(Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.getLineForOffset(3)).isEqualTo(0)
assertThat(paragraph.getLineForOffset(7)).isEqualTo(1)
@@ -2466,7 +2466,7 @@
val paragraph = simpleParagraph(
text = text,
- constraints = ParagraphConstraints(Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.getLineForOffset(-1)).isEqualTo(0)
assertThat(paragraph.getLineForOffset(-2)).isEqualTo(0)
@@ -2484,7 +2484,7 @@
maxLines = 1,
ellipsis = true,
style = TextStyle(),
- constraints = ParagraphConstraints(Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
for (i in 0..2) {
@@ -2514,7 +2514,7 @@
fontFamily = fontFamilyMeasureFont,
fontSize = fontSize.sp
),
- constraints = ParagraphConstraints(fontSize * 3)
+ width = fontSize * 3
)
// Prerequisite check for the this test.
@@ -2530,7 +2530,7 @@
val paragraph = simpleParagraph(
text = text,
- constraints = ParagraphConstraints(Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
// Prerequisite check for the this test.
@@ -2547,7 +2547,7 @@
val paragraph = simpleParagraph(
text = text,
- constraints = ParagraphConstraints(Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
// Prerequisite check for the this test.
@@ -2567,7 +2567,7 @@
fontFamily = fontFamilyMeasureFont,
fontSize = fontSize.sp
),
- constraints = ParagraphConstraints(fontSize * 3),
+ width = fontSize * 3,
density = defaultDensity
)
@@ -2583,7 +2583,7 @@
val paragraph = simpleParagraph(
text = text,
- constraints = ParagraphConstraints(Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
// Prerequisite check for the this test.
@@ -2598,7 +2598,7 @@
val paragraph = simpleParagraph(
text = text,
- constraints = ParagraphConstraints(Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
// Prerequisite check for the this test.
@@ -2615,7 +2615,7 @@
text = text,
maxLines = 2,
ellipsis = true,
- constraints = ParagraphConstraints(Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.lineCount).isEqualTo(2)
@@ -2640,7 +2640,7 @@
),
maxLines = 2,
ellipsis = true,
- constraints = ParagraphConstraints(50f)
+ width = 50f
)
// Prerequisite check for the this test.
@@ -2675,7 +2675,7 @@
fontSize = fontSize.sp,
lineHeight = lineHeight.sp
),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
assertThat(paragraph.lineCount).isEqualTo(4)
@@ -2701,7 +2701,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize.sp, lineHeight = lineHeight.em),
- constraints = ParagraphConstraints(width = layoutWidth)
+ width = layoutWidth
)
assertThat(paragraph.lineCount).isEqualTo(4)
@@ -2728,7 +2728,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
// Make sure there is only one line, so that we can use getLineRight to test fontSize.
@@ -2753,7 +2753,7 @@
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
// Make sure there is only one line, so that we can use getLineRight to test fontSize.
@@ -2784,7 +2784,7 @@
AnnotatedString.Range(spanStyle, 0, text.length),
AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
// Make sure there is only one line, so that we can use getLineRight to test fontSize.
@@ -2938,7 +2938,7 @@
text = text,
style = TextStyle(fontSize = fontSize),
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.lineCount).isEqualTo(1)
@@ -2961,7 +2961,7 @@
text = text,
style = TextStyle(fontSize = fontSize),
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.lineCount).isEqualTo(1)
@@ -2984,7 +2984,7 @@
text = text,
style = TextStyle(fontSize = fontSize),
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3013,7 +3013,7 @@
AnnotatedString.Range(spanStyle, 0, text.length),
AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3045,7 +3045,7 @@
AnnotatedString.Range(letterSpacingStyle, 0, text.length),
AnnotatedString.Range(fontSizeStyle, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3076,7 +3076,7 @@
AnnotatedString.Range(letterSpacingStyle, 0, text.length),
AnnotatedString.Range(scaleXStyle, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3109,7 +3109,7 @@
AnnotatedString.Range(letterSpacingStyle, 0, text.length),
AnnotatedString.Range(fontSizeStyle, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3141,7 +3141,7 @@
AnnotatedString.Range(letterSpacingStyle, 0, text.length),
AnnotatedString.Range(scaleXStyle, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3171,7 +3171,7 @@
AnnotatedString.Range(letterSpacingEmStyle, 0, text.length),
AnnotatedString.Range(letterSpacingSpStyle, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3201,7 +3201,7 @@
AnnotatedString.Range(letterSpacingSpStyle, 0, "abc".length),
AnnotatedString.Range(letterSpacingEmStyle, 0, text.length)
),
- constraints = ParagraphConstraints(width = 500f)
+ width = 500f
)
assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3252,7 +3252,7 @@
textIndent = TextIndent(firstLine = indent.sp),
fontFamily = fontFamilyMeasureFont
),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
assertThat(paragraph.lineCount).isEqualTo(2)
@@ -3275,7 +3275,7 @@
fontSize = fontSize.sp,
fontFamily = fontFamilyMeasureFont
),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
// check the position of the first character in second line: "d" should be indented
@@ -3319,7 +3319,7 @@
fontSize = fontSize.sp,
fontFamily = fontFamilyMeasureFont
),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
assertThat(paragraph.lineCount).isEqualTo(2)
@@ -3343,7 +3343,7 @@
fontSize = fontSize.sp,
fontFamily = fontFamilyMeasureFont
),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
assertThat(paragraph.lineCount).isEqualTo(2)
@@ -3428,12 +3428,12 @@
spanStyles = listOf(
AnnotatedString.Range(spanStyle, 0, text.length)
),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
val paragraph = simpleParagraph(
text = text,
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
assertThat(paragraphShadow.bitmap()).isNotEqualToBitmap(paragraph.bitmap())
@@ -3452,7 +3452,7 @@
val paragraphWithoutColor = simpleParagraph(
text = text,
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(paragraphWidth)
+ width = paragraphWidth
)
val paragraphWithColor = simpleParagraph(
@@ -3461,7 +3461,7 @@
color = Color.Red,
fontSize = fontSize
),
- constraints = ParagraphConstraints(paragraphWidth)
+ width = paragraphWidth
)
assertThat(paragraphWithColor.bitmap())
@@ -3980,7 +3980,7 @@
val paragraph = Paragraph(
paragraphIntrinsics = paragraphIntrinsics,
- constraints = ParagraphConstraints(fontSizeInPx * text.length)
+ width = fontSizeInPx * text.length
)
assertThat(paragraph.maxIntrinsicWidth).isEqualTo(paragraphIntrinsics.maxIntrinsicWidth)
@@ -3993,7 +3993,15 @@
simpleParagraph(
text = "",
maxLines = -1,
- constraints = ParagraphConstraints(Float.MAX_VALUE)
+ width = Float.MAX_VALUE
+ )
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun negativeWidth_throwsException() {
+ simpleParagraph(
+ text = "",
+ width = -1f
)
}
@@ -4004,7 +4012,7 @@
ellipsis: Boolean = false,
spanStyles: List<AnnotatedString.Range<SpanStyle>> = listOf(),
density: Density? = null,
- constraints: ParagraphConstraints = ParagraphConstraints(Float.MAX_VALUE)
+ width: Float = Float.MAX_VALUE
): Paragraph {
return Paragraph(
text = text,
@@ -4014,7 +4022,7 @@
).merge(style),
maxLines = maxLines,
ellipsis = ellipsis,
- constraints = constraints,
+ width = width,
density = density ?: defaultDensity,
resourceLoader = TestFontResourceLoader(context)
)
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTextDirectionTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTextDirectionTest.kt
index 08ffa20..ba0be8f 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTextDirectionTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTextDirectionTest.kt
@@ -59,7 +59,7 @@
val paragraph = Paragraph(
text = "",
style = TextStyle(textDirection = null),
- constraints = ParagraphConstraints(Float.MAX_VALUE),
+ width = Float.MAX_VALUE,
density = defaultDensity,
resourceLoader = resourceLoader
)
@@ -74,7 +74,7 @@
val paragraph = Paragraph(
text = "",
style = TextStyle(textDirection = null),
- constraints = ParagraphConstraints(Float.MAX_VALUE),
+ width = Float.MAX_VALUE,
density = defaultDensity,
resourceLoader = resourceLoader
)
@@ -87,7 +87,7 @@
val paragraph = Paragraph(
text = "",
style = TextStyle(textDirection = null, localeList = ltrLocaleList),
- constraints = ParagraphConstraints(Float.MAX_VALUE),
+ width = Float.MAX_VALUE,
density = defaultDensity,
resourceLoader = resourceLoader
)
@@ -100,7 +100,7 @@
val paragraph = Paragraph(
text = "",
style = TextStyle(textDirection = null, localeList = rtlLocaleList),
- constraints = ParagraphConstraints(Float.MAX_VALUE),
+ width = Float.MAX_VALUE,
density = defaultDensity,
resourceLoader = resourceLoader
)
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphPlaceholderIntegrationTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphPlaceholderIntegrationTest.kt
index a4f55a4..a584a20 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphPlaceholderIntegrationTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphPlaceholderIntegrationTest.kt
@@ -521,7 +521,7 @@
placeholders = placeholders,
maxLines = maxLines,
ellipsis = ellipsis,
- constraints = ParagraphConstraints(width = width),
+ width = width,
density = defaultDensity,
resourceLoader = TestFontResourceLoader(context)
)
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/platform/AndroidParagraphTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/platform/AndroidParagraphTest.kt
index 3cf048d..1f6d7b6 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/platform/AndroidParagraphTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/platform/AndroidParagraphTest.kt
@@ -17,7 +17,6 @@
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.FontTestData.Companion.BASIC_MEASURE_FONT
-import androidx.compose.ui.text.ParagraphConstraints
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TestFontResourceLoader
import androidx.compose.ui.text.TextStyle
@@ -85,7 +84,7 @@
fontFamily = basicFontFamily
),
// 2 chars width
- constraints = ParagraphConstraints(width = 2 * fontSize.toPx())
+ width = 2 * fontSize.toPx()
)
val textPaint = TextPaint(Paint.ANTI_ALIAS_FLAG)
@@ -111,7 +110,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence).hasSpan(ForegroundColorSpan::class, 0, text.length)
@@ -125,7 +124,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence).hasSpan(ForegroundColorSpan::class, 0, "abc".length)
@@ -143,7 +142,7 @@
AnnotatedString.Range(spanStyle, 0, text.length),
AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence).hasSpan(ForegroundColorSpan::class, 0, text.length)
@@ -159,7 +158,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -174,7 +173,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -189,7 +188,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -204,7 +203,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -221,7 +220,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -240,7 +239,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
assertThat(paragraph.charSequence).hasSpan(AbsoluteSizeSpan::class, 0, text.length)
@@ -258,7 +257,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
assertThat(paragraph.charSequence).hasSpan(AbsoluteSizeSpan::class, 0, "abc".length)
@@ -281,7 +280,7 @@
AnnotatedString.Range(spanStyle, 0, text.length),
AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
assertThat(paragraph.charSequence).hasSpan(AbsoluteSizeSpan::class, 0, text.length)
@@ -300,7 +299,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence).hasSpan(RelativeSizeSpan::class, 0, text.length) {
@@ -317,7 +316,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence).hasSpan(RelativeSizeSpan::class, 0, "abc".length) {
@@ -334,7 +333,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -349,7 +348,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -368,7 +367,7 @@
AnnotatedString.Range(spanStyle, 0, text.length),
AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -386,7 +385,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -405,7 +404,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -429,7 +428,7 @@
AnnotatedString.Range(spanStyle, 0, text.length),
AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -456,7 +455,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence).hasSpan(LocaleSpan::class, 0, text.length)
@@ -471,7 +470,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence).hasSpan(LocaleSpan::class, 0, "abc".length)
@@ -489,7 +488,7 @@
AnnotatedString.Range(spanStyle, 0, text.length),
AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence).hasSpan(LocaleSpan::class, 0, text.length)
@@ -505,7 +504,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = 100.0f) // width is not important
+ width = 100.0f // width is not important
)
assertThat(paragraph.charSequence).hasSpan(BaselineShiftSpan::class, 0, text.length)
@@ -519,7 +518,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
- constraints = ParagraphConstraints(width = 100.0f) // width is not important
+ width = 100.0f // width is not important
)
assertThat(paragraph.charSequence).hasSpan(BaselineShiftSpan::class, 0, "abc".length)
@@ -538,7 +537,7 @@
AnnotatedString.Range(spanStyle, 0, text.length),
AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
),
- constraints = ParagraphConstraints(width = 100.0f) // width is not important
+ width = 100.0f // width is not important
)
assertThat(paragraph.charSequence).hasSpan(BaselineShiftSpan::class, 0, text.length)
@@ -554,7 +553,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = 100.0f) // width is not important
+ width = 100.0f // width is not important
)
assertThat(paragraph.charSequence).spans(ScaleXSpan::class).isEmpty()
@@ -574,7 +573,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = 100.0f) // width is not important
+ width = 100.0f // width is not important
)
assertThat(paragraph.charSequence).hasSpan(ScaleXSpan::class, 0, text.length) {
@@ -592,7 +591,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
- constraints = ParagraphConstraints(width = 100.0f) // width is not important
+ width = 100.0f // width is not important
)
assertThat(paragraph.charSequence).hasSpan(SkewXSpan::class, 0, text.length) {
@@ -610,7 +609,7 @@
val paragraph = simpleParagraph(
text = text,
textIndent = TextIndent(firstLine.sp, restLine.sp),
- constraints = ParagraphConstraints(width = 100.0f) // width is not important
+ width = 100.0f // width is not important
)
assertThat(paragraph.charSequence)
@@ -632,7 +631,7 @@
spanStyles = listOf(
AnnotatedString.Range(spanStyle, start = 0, end = text.length)
),
- constraints = ParagraphConstraints(width = 100.0f) // width is not important
+ width = 100.0f // width is not important
)
assertThat(paragraph.charSequence)
@@ -665,7 +664,7 @@
AnnotatedString.Range(spanStyle, start = 0, end = text.length),
AnnotatedString.Range(spanStyleOverwrite, start = 0, end = "abc".length)
),
- constraints = ParagraphConstraints(width = 100.0f) // width is not important
+ width = 100.0f // width is not important
)
assertThat(paragraph.charSequence)
@@ -709,7 +708,7 @@
expectedEnd
)
),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -746,7 +745,7 @@
expectedEnd
)
),
- constraints = ParagraphConstraints(width = 100.0f)
+ width = 100.0f
)
assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -765,7 +764,7 @@
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
- constraints = ParagraphConstraints(width = 100.0f) // width is not important
+ width = 100.0f // width is not important
)
assertThat(paragraph.charSequence).hasSpan(FontFeatureSpan::class, 0, "abc".length) {
@@ -779,7 +778,7 @@
val paragraph = simpleParagraph(
text = "abc",
typefaceAdapter = typefaceAdapter,
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
verify(typefaceAdapter, never()).create(
@@ -802,7 +801,7 @@
fontWeight = FontWeight.Bold
),
typefaceAdapter = typefaceAdapter,
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
verify(typefaceAdapter, times(1)).create(
@@ -828,7 +827,7 @@
fontStyle = FontStyle.Italic
),
typefaceAdapter = typefaceAdapter,
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
verify(typefaceAdapter, times(1)).create(
@@ -855,7 +854,7 @@
fontFamily = fontFamily
),
typefaceAdapter = typefaceAdapter,
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
verify(typefaceAdapter, times(1)).create(
@@ -880,7 +879,7 @@
fontFamily = basicFontFamily
),
typefaceAdapter = typefaceAdapter,
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
verify(typefaceAdapter, atLeastOnce()).create(
@@ -904,7 +903,7 @@
fontFamily = basicFontFamily
),
typefaceAdapter = typefaceAdapter,
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
val charSequence = paragraph.charSequence
@@ -924,7 +923,7 @@
fontSize = fontSize
),
ellipsis = true,
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
for (i in 0 until paragraph.lineCount) {
@@ -948,7 +947,7 @@
fontFamily = basicFontFamily,
fontSize = fontSize
),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
assertThat(paragraph.isEllipsisApplied(0)).isTrue()
@@ -970,7 +969,7 @@
fontFamily = basicFontFamily,
fontSize = fontSize
),
- constraints = ParagraphConstraints(width = paragraphWidth)
+ width = paragraphWidth
)
for (i in 0 until paragraph.lineCount) {
@@ -986,7 +985,7 @@
val paragraph = simpleParagraph(
text = "",
style = TextStyle(fontSize = fontSize),
- constraints = ParagraphConstraints(width = 0.0f)
+ width = 0.0f
)
assertThat(paragraph.textPaint.textSize).isEqualTo(fontSize.toPx())
@@ -1001,7 +1000,7 @@
val paragraph = simpleParagraph(
text = "",
style = TextStyle(localeList = localeList),
- constraints = ParagraphConstraints(width = 0.0f)
+ width = 0.0f
)
assertThat(paragraph.textPaint.textLocale.language).isEqualTo(platformLocale.language)
@@ -1014,7 +1013,7 @@
val paragraph = simpleParagraph(
text = "",
style = TextStyle(color = color),
- constraints = ParagraphConstraints(width = 0.0f)
+ width = 0.0f
)
assertThat(paragraph.textPaint.color).isEqualTo(color.toArgb())
@@ -1026,7 +1025,7 @@
val paragraph = simpleParagraph(
text = "",
style = TextStyle(letterSpacing = letterSpacing.em),
- constraints = ParagraphConstraints(width = 0.0f)
+ width = 0.0f
)
assertThat(paragraph.textPaint.letterSpacing).isEqualTo((letterSpacing))
@@ -1039,7 +1038,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(letterSpacing = letterSpacing.sp),
- constraints = ParagraphConstraints(width = 0.0f)
+ width = 0.0f
)
assertThat(paragraph.charSequence)
@@ -1054,7 +1053,7 @@
val paragraph = simpleParagraph(
text = "",
style = TextStyle(fontFeatureSettings = fontFeatureSettings),
- constraints = ParagraphConstraints(width = 0.0f)
+ width = 0.0f
)
assertThat(paragraph.textPaint.fontFeatureSettings).isEqualTo(fontFeatureSettings)
@@ -1070,7 +1069,7 @@
scaleX = scaleX
)
),
- constraints = ParagraphConstraints(width = 0.0f)
+ width = 0.0f
)
assertThat(paragraph.textPaint.textScaleX).isEqualTo(scaleX)
@@ -1086,7 +1085,7 @@
skewX = skewX
)
),
- constraints = ParagraphConstraints(width = 0.0f)
+ width = 0.0f
)
assertThat(paragraph.textPaint.textSkewX).isEqualTo(skewX)
@@ -1097,7 +1096,7 @@
val paragraph = simpleParagraph(
text = "",
style = TextStyle(textDecoration = TextDecoration.Underline),
- constraints = ParagraphConstraints(width = 0.0f)
+ width = 0.0f
)
assertThat(paragraph.textPaint.isUnderlineText).isTrue()
@@ -1108,7 +1107,7 @@
val paragraph = simpleParagraph(
text = "",
style = TextStyle(textDecoration = TextDecoration.LineThrough),
- constraints = ParagraphConstraints(width = 0.0f)
+ width = 0.0f
)
assertThat(paragraph.textPaint.isStrikeThruText).isTrue()
@@ -1123,7 +1122,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(background = color),
- constraints = ParagraphConstraints(width = 0.0f)
+ width = 0.0f
)
assertThat(paragraph.charSequence)
@@ -1141,7 +1140,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(baselineShift = baselineShift),
- constraints = ParagraphConstraints(width = 0.0f)
+ width = 0.0f
)
assertThat(paragraph.charSequence)
@@ -1155,7 +1154,7 @@
val text = "abc"
val paragraph = simpleParagraph(
text = text,
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.textLocale.toLanguageTag())
@@ -1169,7 +1168,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(localeList = localeList),
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.textLocale.toLanguageTag()).isEqualTo("en-US")
@@ -1182,7 +1181,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(localeList = localeList),
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.textLocale.toLanguageTag()).isEqualTo("ja-JP")
@@ -1195,7 +1194,7 @@
val paragraph = simpleParagraph(
text = text,
style = TextStyle(localeList = localeList),
- constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+ width = Float.MAX_VALUE
)
assertThat(paragraph.textLocale.toLanguageTag()).isEqualTo("ja")
@@ -1206,7 +1205,7 @@
val floatWidth = 1.3f
val paragraph = simpleParagraph(
text = "Hello, World",
- constraints = ParagraphConstraints(floatWidth)
+ width = floatWidth
)
assertThat(floatWidth).isEqualTo(paragraph.width)
@@ -1219,7 +1218,7 @@
textAlign: TextAlign? = null,
ellipsis: Boolean = false,
maxLines: Int = Int.MAX_VALUE,
- constraints: ParagraphConstraints,
+ width: Float,
style: TextStyle? = null,
typefaceAdapter: TypefaceAdapter = TypefaceAdapter()
): AndroidParagraph {
@@ -1234,7 +1233,7 @@
).merge(style),
maxLines = maxLines,
ellipsis = ellipsis,
- constraints = constraints,
+ width = width,
density = Density(density = 1f)
)
}
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.kt
index d9e82af..df3b7c3 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.kt
@@ -28,7 +28,6 @@
import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.Paragraph
-import androidx.compose.ui.text.ParagraphConstraints
import androidx.compose.ui.text.ParagraphIntrinsics
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.SpanStyle
@@ -64,7 +63,7 @@
val paragraphIntrinsics: AndroidParagraphIntrinsics,
val maxLines: Int,
val ellipsis: Boolean,
- val constraints: ParagraphConstraints
+ override val width: Float
) : Paragraph {
constructor(
@@ -74,7 +73,7 @@
placeholders: List<AnnotatedString.Range<Placeholder>>,
maxLines: Int,
ellipsis: Boolean,
- constraints: ParagraphConstraints,
+ width: Float,
typefaceAdapter: TypefaceAdapter,
density: Density
) : this(
@@ -88,15 +87,14 @@
),
maxLines = maxLines,
ellipsis = ellipsis,
- constraints = constraints
+ width = width
)
private val layout: TextLayout
- override val width: Float
-
init {
require(maxLines >= 1) { "maxLines should be greater than 0" }
+ require(width >= 0f) { "width should not be negative" }
val style = paragraphIntrinsics.style
@@ -113,11 +111,9 @@
null
}
- this.width = constraints.width
-
layout = TextLayout(
charSequence = paragraphIntrinsics.charSequence,
- width = constraints.width,
+ width = width,
textPaint = textPaint,
ellipsize = ellipsize,
alignment = alignment,
@@ -375,7 +371,7 @@
placeholders: List<AnnotatedString.Range<Placeholder>>,
maxLines: Int,
ellipsis: Boolean,
- constraints: ParagraphConstraints,
+ width: Float,
density: Density,
resourceLoader: Font.ResourceLoader
): Paragraph = AndroidParagraph(
@@ -391,17 +387,17 @@
),
maxLines,
ellipsis,
- constraints
+ width
)
internal actual fun ActualParagraph(
paragraphIntrinsics: ParagraphIntrinsics,
maxLines: Int,
ellipsis: Boolean,
- constraints: ParagraphConstraints
+ width: Float
): Paragraph = AndroidParagraph(
paragraphIntrinsics as AndroidParagraphIntrinsics,
maxLines,
ellipsis,
- constraints
+ width
)
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
index 9e4f8bc..4ce14e5 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
@@ -36,12 +36,13 @@
* @param intrinsics previously calculated text intrinsics
* @param maxLines the maximum number of lines that the text can have
* @param ellipsis whether to ellipsize text, applied only when [maxLines] is set
+ * @param width how wide the text is allowed to be
*/
class MultiParagraph(
val intrinsics: MultiParagraphIntrinsics,
val maxLines: Int = DefaultMaxLines,
ellipsis: Boolean = false,
- constraints: ParagraphConstraints
+ width: Float
) {
/**
@@ -56,7 +57,7 @@
* thrown.
* @param maxLines the maximum number of lines that the text can have
* @param ellipsis whether to ellipsize text, applied only when [maxLines] is set
- * @param constraints how wide the text is allowed to be
+ * @param width how wide the text is allowed to be
* @param density density of the device
* @param resourceLoader [Font.ResourceLoader] to be used to load the font given in [SpanStyle]s
*
@@ -70,7 +71,7 @@
placeholders: List<AnnotatedString.Range<Placeholder>> = listOf(),
maxLines: Int = Int.MAX_VALUE,
ellipsis: Boolean = false,
- constraints: ParagraphConstraints,
+ width: Float,
density: Density,
resourceLoader: Font.ResourceLoader
) : this(
@@ -83,7 +84,7 @@
),
maxLines = maxLines,
ellipsis = ellipsis,
- constraints = constraints
+ width = width
)
private val annotatedString get() = intrinsics.annotatedString
@@ -178,7 +179,7 @@
paragraphInfo.intrinsics,
maxLines - currentLineCount,
ellipsis,
- constraints
+ width
)
val paragraphTop = currentHeight
@@ -212,7 +213,7 @@
this.lineCount = currentLineCount
this.didExceedMaxLines = didExceedMaxLines
this.paragraphInfoList = paragraphInfoList
- this.width = constraints.width
+ this.width = width
this.placeholderRects = paragraphInfoList.flatMap { paragraphInfo ->
with(paragraphInfo) {
paragraph.placeholderRects.map { it?.toGlobal() }
@@ -763,7 +764,7 @@
* [MultiParagraph].
*/
fun Rect.toGlobal(): Rect {
- return shift(Offset(0f, this@ParagraphInfo.top))
+ return translate(Offset(0f, this@ParagraphInfo.top))
}
/**
@@ -773,7 +774,7 @@
* Notice that this function changes the input value.
*/
fun Path.toGlobal(): Path {
- shift(Offset(0f, top))
+ translate(Offset(0f, top))
return this
}
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/Paragraph.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/Paragraph.kt
index 197cce4..2f53bcd 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/Paragraph.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/Paragraph.kt
@@ -263,7 +263,7 @@
* be left blank to leave space for inline elements.
* @param maxLines the maximum number of lines that the text can have
* @param ellipsis whether to ellipsize text, applied only when [maxLines] is set
- * @param constraints how wide the text is allowed to be
+ * @param width how wide the text is allowed to be
* @param density density of the device
* @param resourceLoader [Font.ResourceLoader] to be used to load the font given in [SpanStyle]s
*
@@ -276,7 +276,7 @@
placeholders: List<AnnotatedString.Range<Placeholder>> = listOf(),
maxLines: Int = DefaultMaxLines,
ellipsis: Boolean = false,
- constraints: ParagraphConstraints,
+ width: Float,
density: Density,
resourceLoader: Font.ResourceLoader
): Paragraph = ActualParagraph(
@@ -286,7 +286,7 @@
placeholders,
maxLines,
ellipsis,
- constraints,
+ width,
density,
resourceLoader
)
@@ -298,16 +298,16 @@
* @param paragraphIntrinsics [ParagraphIntrinsics] instance
* @param maxLines the maximum number of lines that the text can have
* @param ellipsis whether to ellipsize text, applied only when [maxLines] is set
- * @param constraints how wide the text is allowed to be
+ * @param width how wide the text is allowed to be
*/
fun Paragraph(
paragraphIntrinsics: ParagraphIntrinsics,
maxLines: Int = DefaultMaxLines,
ellipsis: Boolean = false,
- constraints: ParagraphConstraints
+ width: Float
): Paragraph = ActualParagraph(
paragraphIntrinsics,
maxLines,
ellipsis,
- constraints
+ width
)
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ParagraphConstraints.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ParagraphConstraints.kt
deleted file mode 100644
index dfbbf72..0000000
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ParagraphConstraints.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2018 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 androidx.compose.ui.text
-
-/**
- * Layout constraints for [Paragraph] objects.
- *
- * Instances of this class are typically used with [Paragraph].
- *
- * The only constraint that can be specified is the [width]. See the discussion
- * at [width] for more details.
- *
- * Creates constraints for laying out a paragraph.
- *
- * The [width] argument must not be null.
- *
- * The width the paragraph should use whey computing the positions of glyphs.
- *
- * If possible, the paragraph will select a soft line break prior to reaching
- * this width. If no soft line break is available, the paragraph will select
- * a hard line break prior to reaching this width. If that would force a line
- * break without any characters having been placed (i.e. if the next
- * character to be laid out does not fit within the given width constraint)
- * then the next character is allowed to overflow the width constraint and a
- * forced line break is placed after it (even if an explicit line break
- * follows).
- *
- * The width influences how ellipses are applied.
- *
- * This width is also used to position glyphs according to the text alignment
- * described in the [ParagraphStyle.textAlign] to create [Paragraph].
- */
-data class ParagraphConstraints(val width: Float) {
- override fun toString(): String {
- return "ParagraphConstraints(width: $width)"
- }
-}
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextDelegate.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextDelegate.kt
index cc64073..2d8e528 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextDelegate.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextDelegate.kt
@@ -156,7 +156,7 @@
intrinsics = nonNullIntrinsics,
maxLines = maxLines,
ellipsis = overflow == TextOverflow.Ellipsis,
- constraints = ParagraphConstraints(width = width)
+ width = width
)
}
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextLayoutResult.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextLayoutResult.kt
index 1ca036f..957741f 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextLayoutResult.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextLayoutResult.kt
@@ -359,7 +359,7 @@
multiParagraph: MultiParagraph = MultiParagraph(
annotatedString = layoutInput.text,
style = layoutInput.style,
- constraints = ParagraphConstraints(width = 0f),
+ width = 0f,
density = layoutInput.density,
resourceLoader = layoutInput.resourceLoader
),
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextRange.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextRange.kt
index d8f4c44..0c79edc 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextRange.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextRange.kt
@@ -18,6 +18,9 @@
import androidx.compose.runtime.Immutable
import androidx.compose.ui.util.annotation.IntRange
+import androidx.compose.ui.util.packInts
+import androidx.compose.ui.util.unpackInt1
+import androidx.compose.ui.util.unpackInt2
fun CharSequence.substring(range: TextRange): String = this.substring(range.min, range.max)
@@ -25,14 +28,30 @@
* An immutable text range class, represents a text range from [start] (inclusive) to [end]
* (exclusive). [end] can be smaller than [start] and in those cases [min] and [max] can be
* used in order to fetch the values.
- *
- * @param start the inclusive start offset of the range. Must be non-negative, otherwise an
- * exception will be thrown.
- * @param end the exclusive end offset of the range. Must be non-negative, otherwise an
- * exception will be thrown.
*/
+@Suppress("EXPERIMENTAL_FEATURE_WARNING")
@Immutable
-data class TextRange(@IntRange(from = 0) val start: Int, @IntRange(from = 0) val end: Int) {
+inline class TextRange(val packedValue: Long) {
+
+ /**
+ * An immutable text range class, represents a text range from [start] (inclusive) to [end]
+ * (exclusive). [end] can be smaller than [start] and in those cases [min] and [max] can be
+ * used in order to fetch the values.
+ *
+ * @param start the inclusive start offset of the range. Must be non-negative, otherwise an
+ * exception will be thrown.
+ * @param end the exclusive end offset of the range. Must be non-negative, otherwise an
+ * exception will be thrown.
+ */
+ constructor(
+ @IntRange(from = 0) start: Int,
+ @IntRange(from = 0) end: Int
+ ) : this(packWithCheck(start, end))
+
+ val start: Int get() = unpackInt1(packedValue)
+
+ val end: Int get() = unpackInt2(packedValue)
+
/** The minimum offset of the range. */
val min: Int get() = if (start > end) end else start
@@ -54,15 +73,6 @@
*/
val length: Int get() = max - min
- init {
- require(start >= 0) {
- "start cannot be negative. [start: $start]"
- }
- require(end >= 0) {
- "end cannot negative. [end: $end]"
- }
- }
-
/**
* Returns true if the given range has intersection with this range
*/
@@ -78,6 +88,10 @@
*/
operator fun contains(offset: Int): Boolean = offset in min until max
+ override fun toString(): String {
+ return "TextRange($start, $end)"
+ }
+
companion object {
val Zero = TextRange(0)
}
@@ -107,4 +121,14 @@
return TextRange(newStart, newEnd)
}
return this
+}
+
+private fun packWithCheck(start: Int, end: Int): Long {
+ require(start >= 0) {
+ "start cannot be negative. [start: $start]"
+ }
+ require(end >= 0) {
+ "end cannot negative. [end: $end]"
+ }
+ return packInts(start, end)
}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/platform/PlatformParagraph.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/platform/PlatformParagraph.kt
index 78f32e0..76d54e0 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/platform/PlatformParagraph.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/platform/PlatformParagraph.kt
@@ -17,7 +17,6 @@
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.Paragraph
-import androidx.compose.ui.text.ParagraphConstraints
import androidx.compose.ui.text.ParagraphIntrinsics
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.SpanStyle
@@ -33,7 +32,7 @@
placeholders: List<AnnotatedString.Range<Placeholder>>,
maxLines: Int,
ellipsis: Boolean,
- constraints: ParagraphConstraints,
+ width: Float,
density: Density,
resourceLoader: Font.ResourceLoader
): Paragraph
@@ -43,7 +42,7 @@
paragraphIntrinsics: ParagraphIntrinsics,
maxLines: Int,
ellipsis: Boolean,
- constraints: ParagraphConstraints
+ width: Float
): Paragraph
// TODO(b/157854677): remove after fixing.
diff --git a/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopParagraph.kt b/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopParagraph.kt
index c9ac5b6..ab132e3 100644
--- a/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopParagraph.kt
+++ b/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopParagraph.kt
@@ -28,7 +28,6 @@
import androidx.compose.ui.graphics.toComposeRect
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.Paragraph
-import androidx.compose.ui.text.ParagraphConstraints
import androidx.compose.ui.text.ParagraphIntrinsics
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
@@ -72,7 +71,7 @@
placeholders: List<AnnotatedString.Range<Placeholder>>,
maxLines: Int,
ellipsis: Boolean,
- constraints: ParagraphConstraints,
+ width: Float,
density: Density,
resourceLoader: Font.ResourceLoader
): Paragraph = DesktopParagraph(
@@ -86,7 +85,7 @@
),
maxLines,
ellipsis,
- constraints
+ width
)
@Suppress("UNUSED_PARAMETER")
@@ -94,19 +93,19 @@
paragraphIntrinsics: ParagraphIntrinsics,
maxLines: Int,
ellipsis: Boolean,
- constraints: ParagraphConstraints
+ width: Float
): Paragraph = DesktopParagraph(
paragraphIntrinsics as DesktopParagraphIntrinsics,
maxLines,
ellipsis,
- constraints
+ width
)
internal class DesktopParagraph(
intrinsics: ParagraphIntrinsics,
val maxLines: Int,
val ellipsis: Boolean,
- val constraints: ParagraphConstraints
+ override val width: Float
) : Paragraph {
val paragraphIntrinsics = intrinsics as DesktopParagraphIntrinsics
@@ -122,15 +121,12 @@
if (resetMaxLinesIfNeeded()) {
rebuildParagraph()
}
- para.layout(constraints.width)
+ para.layout(width)
}
private val text: String
get() = paragraphIntrinsics.text
- override val width: Float
- get() = para.getMaxWidth()
-
override val height: Float
get() = para.getHeight()
@@ -339,7 +335,7 @@
textDecoration = currentTextDecoration
)
rebuildParagraph()
- para.layout(constraints.width)
+ para.layout(width)
}
para.paint(canvas.nativeCanvas, 0.0f, 0.0f)
}
diff --git a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/ParagraphConstraintsTest.kt b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/ParagraphConstraintsTest.kt
deleted file mode 100644
index a1d78da..0000000
--- a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/ParagraphConstraintsTest.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2019 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 androidx.compose.ui.text
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ParagraphConstraintsTest {
-
- @Test
- fun `toString with values`() {
- val paragraphConstraints = ParagraphConstraints(width = 101.0f)
- assertThat(paragraphConstraints.toString()).isEqualTo("ParagraphConstraints(width: 101.0)")
- }
-}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextRangeTest.kt b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextRangeTest.kt
index 819402c..3af74a5 100644
--- a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextRangeTest.kt
+++ b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextRangeTest.kt
@@ -139,23 +139,11 @@
}
@Test
- fun constrain_returns_same_object_if_no_change_required() {
- val textRange = TextRange(1, 2)
- assertThat(textRange.constrain(0, 3)).isSameInstanceAs(textRange)
- }
-
- @Test
fun constrain_updates_start_end_if_required() {
assertThat(TextRange(0, 4).constrain(1, 3)).isEqualTo(TextRange(1, 3))
}
@Test
- fun constrain_collapsed_TextRange_with_the_same_min_max_returns_the_same_instance() {
- val textRange = TextRange(2, 2)
- assertThat(textRange.constrain(2, 2)).isSameInstanceAs(textRange)
- }
-
- @Test
fun constrain_with_collapsed_min_max_returns_collapsed_values() {
assertThat(TextRange(1, 2).constrain(2, 2)).isEqualTo(TextRange(2, 2))
assertThat(TextRange(2, 3).constrain(2, 2)).isEqualTo(TextRange(2, 2))
@@ -170,4 +158,10 @@
fun constrain_min_smaller_than_TextRange_values() {
assertThat(TextRange(5, 6).constrain(0, 4)).isEqualTo(TextRange(4, 4))
}
+
+ @Test
+ fun to_string() {
+ assertThat(TextRange(0, 1).toString()).isEqualTo("TextRange(0, 1)")
+ assertThat(TextRange(1, 1).toString()).isEqualTo("TextRange(1, 1)")
+ }
}
\ No newline at end of file
diff --git a/compose/ui/ui-unit/samples/build.gradle b/compose/ui/ui-unit/samples/build.gradle
index 500b2cc..1a87f7a 100644
--- a/compose/ui/ui-unit/samples/build.gradle
+++ b/compose/ui/ui-unit/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/ui/ui-viewbinding/build.gradle b/compose/ui/ui-viewbinding/build.gradle
index 940c8fe..1a4e04be 100644
--- a/compose/ui/ui-viewbinding/build.gradle
+++ b/compose/ui/ui-viewbinding/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
implementation project(":compose:ui:ui")
diff --git a/compose/ui/ui-viewbinding/samples/build.gradle b/compose/ui/ui-viewbinding/samples/build.gradle
index e087672..ac7eed9 100644
--- a/compose/ui/ui-viewbinding/samples/build.gradle
+++ b/compose/ui/ui-viewbinding/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
implementation project(":annotation:annotation-sampled")
diff --git a/compose/ui/ui-viewbinding/src/androidTest/java/androidx/compose/ui/viewinterop/AndroidViewBindingTest.kt b/compose/ui/ui-viewbinding/src/androidTest/java/androidx/compose/ui/viewinterop/AndroidViewBindingTest.kt
index 53cc239..8446139 100644
--- a/compose/ui/ui-viewbinding/src/androidTest/java/androidx/compose/ui/viewinterop/AndroidViewBindingTest.kt
+++ b/compose/ui/ui-viewbinding/src/androidTest/java/androidx/compose/ui/viewinterop/AndroidViewBindingTest.kt
@@ -91,9 +91,12 @@
val density = Density(3f)
val sizeIpx = with(density) { size.toIntPx() }
Providers(DensityAmbient provides density) {
- AndroidViewBinding(TestLayoutBinding::inflate, Modifier.size(size).onPositioned {
- Truth.assertThat(it.size).isEqualTo(IntSize(sizeIpx, sizeIpx))
- })
+ AndroidViewBinding(
+ TestLayoutBinding::inflate,
+ Modifier.size(size).onPositioned {
+ Truth.assertThat(it.size).isEqualTo(IntSize(sizeIpx, sizeIpx))
+ }
+ )
}
}
rule.waitForIdle()
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index ed8a943..8a0333c 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -89,6 +89,16 @@
method public static int merge(androidx.compose.ui.AlignmentLine, int position1, int position2);
}
+ public final class CacheDrawScope implements androidx.compose.ui.unit.Density {
+ method public float getDensity();
+ method public float getFontScale();
+ method public long getSize();
+ method public androidx.compose.ui.DrawResult onDraw(kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+ property public float density;
+ property public float fontScale;
+ property public final long size;
+ }
+
public final class CombinedModifier implements androidx.compose.ui.Modifier {
ctor public CombinedModifier(androidx.compose.ui.Modifier outer, androidx.compose.ui.Modifier inner);
method public boolean all(kotlin.jvm.functions.Function1<? super androidx.compose.ui.Modifier.Element,java.lang.Boolean> predicate);
@@ -107,6 +117,10 @@
method public abstract void drawContent();
}
+ public interface DrawCacheModifier extends androidx.compose.ui.DrawModifier {
+ method public void onBuildCache-lwCvPpU(long size, androidx.compose.ui.unit.Density density);
+ }
+
public interface DrawLayerModifier extends androidx.compose.ui.Modifier.Element {
method @FloatRange(from=0.0, to=1.0) public default float getAlpha();
method public default boolean getClip();
@@ -145,9 +159,13 @@
public final class DrawModifierKt {
method public static androidx.compose.ui.Modifier drawBehind(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> onDraw);
+ method public static androidx.compose.ui.Modifier drawWithCache(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.CacheDrawScope,androidx.compose.ui.DrawResult> onBuildDrawCache);
method public static androidx.compose.ui.Modifier drawWithContent(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.ContentDrawScope,kotlin.Unit> onDraw);
}
+ public final class DrawResult {
+ }
+
public final class FocusModifierKt {
method @androidx.compose.runtime.Composable @androidx.compose.ui.focus.ExperimentalFocus public static androidx.compose.ui.Modifier focus(androidx.compose.ui.Modifier);
}
@@ -277,16 +295,16 @@
public abstract static class Placeable.PlacementScope {
ctor public Placeable.PlacementScope();
- method public abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
- method public abstract int getParentWidth();
+ method protected abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
+ method protected abstract int getParentWidth();
method public final void place(androidx.compose.ui.Placeable, int x, int y);
method public final void place-LmmdDA8(androidx.compose.ui.Placeable, long position);
method public final void place-gl1q84w(androidx.compose.ui.Placeable, long position);
method public final void placeRelative(androidx.compose.ui.Placeable, int x, int y);
method public final void placeRelative-LmmdDA8(androidx.compose.ui.Placeable, long position);
method public final void placeRelative-gl1q84w(androidx.compose.ui.Placeable, long position);
- property public abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
- property public abstract int parentWidth;
+ property protected abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
+ property protected abstract int parentWidth;
}
public interface Remeasurement {
@@ -451,15 +469,6 @@
@kotlin.RequiresOptIn(message="The Focus API is experimental and is likely to change in the future.") public @interface ExperimentalFocus {
}
- @androidx.compose.ui.focus.ExperimentalFocus public final class FocusManager {
- ctor public FocusManager();
- method public void clearFocus();
- method public androidx.compose.ui.Modifier getModifier();
- method public void releaseFocus();
- method public void takeFocus();
- property public final androidx.compose.ui.Modifier modifier;
- }
-
public final class FocusNodeUtilsKt {
}
@@ -1861,6 +1870,7 @@
method public void measureAndLayout();
method public void observeLayoutModelReads(androidx.compose.ui.node.LayoutNode node, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public void observeMeasureModelReads(androidx.compose.ui.node.LayoutNode node, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public <T> void observeReads(T target, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public void onAttach(androidx.compose.ui.node.LayoutNode node);
method public void onDetach(androidx.compose.ui.node.LayoutNode node);
method public void onRequestMeasure(androidx.compose.ui.node.LayoutNode layoutNode);
@@ -1961,14 +1971,12 @@
public interface AndroidOwner extends androidx.compose.ui.node.Owner {
method @androidx.compose.ui.node.ExperimentalLayoutNodeApi public void addAndroidView(android.view.View view, androidx.compose.ui.node.LayoutNode layoutNode);
method public kotlin.jvm.functions.Function1<android.content.res.Configuration,kotlin.Unit> getConfigurationChangeObserver();
- method public androidx.compose.ui.focus.FocusManager getFocusManager();
method public android.view.View getView();
method public androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners? getViewTreeOwners();
method public void removeAndroidView(android.view.View view);
method public void setConfigurationChangeObserver(kotlin.jvm.functions.Function1<? super android.content.res.Configuration,kotlin.Unit> p);
method public void setOnViewTreeOwnersAvailable(kotlin.jvm.functions.Function1<? super androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners,kotlin.Unit> callback);
property public abstract kotlin.jvm.functions.Function1<android.content.res.Configuration,kotlin.Unit> configurationChangeObserver;
- property public abstract androidx.compose.ui.focus.FocusManager focusManager;
property public abstract android.view.View view;
property public abstract androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners? viewTreeOwners;
}
@@ -2158,7 +2166,7 @@
method public boolean getHandlesCrossed();
method public androidx.compose.ui.selection.Selection.AnchorInfo getStart();
method public androidx.compose.ui.selection.Selection merge(androidx.compose.ui.selection.Selection? other);
- method public androidx.compose.ui.text.TextRange toTextRange();
+ method public long toTextRange();
}
@androidx.compose.runtime.Immutable public static final class Selection.AnchorInfo {
@@ -2219,6 +2227,18 @@
method public int getSteps();
}
+ public final class AccessibilityScrollState {
+ ctor public AccessibilityScrollState(float value, float maxValue, boolean reverseScrolling);
+ ctor public AccessibilityScrollState();
+ method public float component1();
+ method public float component2();
+ method public boolean component3();
+ method public androidx.compose.ui.semantics.AccessibilityScrollState copy(float value, float maxValue, boolean reverseScrolling);
+ method public float getMaxValue();
+ method public boolean getReverseScrolling();
+ method public float getValue();
+ }
+
public final class CustomAccessibilityAction {
ctor public CustomAccessibilityAction(CharSequence label, kotlin.jvm.functions.Function0<java.lang.Boolean> action);
method public CharSequence component1();
@@ -2327,22 +2347,26 @@
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getDisabled();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getFocused();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getHidden();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> getHorizontalAccessibilityScrollState();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsDialog();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsPopup();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> getTestTag();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> getText();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.TextRange> getTextSelectionRange();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> getVerticalAccessibilityScrollState();
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> AccessibilityLabel;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityRangeInfo> AccessibilityRangeInfo;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> AccessibilityValue;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Disabled;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> Focused;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Hidden;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> HorizontalAccessibilityScrollState;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsDialog;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsPopup;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> TestTag;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> Text;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.TextRange> TextSelectionRange;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> VerticalAccessibilityScrollState;
field public static final androidx.compose.ui.semantics.SemanticsProperties INSTANCE;
}
@@ -2354,10 +2378,12 @@
method public static androidx.compose.ui.semantics.AccessibilityRangeInfo getAccessibilityValueRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction> getCustomActions(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static boolean getFocused(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static androidx.compose.ui.semantics.AccessibilityScrollState getHorizontalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static String getTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static androidx.compose.ui.text.AnnotatedString getText(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void getTextLayoutResult(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.ui.text.TextLayoutResult>,java.lang.Boolean> action);
- method public static androidx.compose.ui.text.TextRange getTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static long getTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static androidx.compose.ui.semantics.AccessibilityScrollState getVerticalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void hidden(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void onClick(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function0<java.lang.Boolean> action);
method public static void popup(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
@@ -2367,12 +2393,14 @@
method public static void setAccessibilityValueRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityRangeInfo p);
method public static void setCustomActions(androidx.compose.ui.semantics.SemanticsPropertyReceiver, java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction> p);
method public static void setFocused(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean p);
+ method public static void setHorizontalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityScrollState p);
method public static void setProgress(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Boolean> action);
method public static void setSelection(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Boolean,java.lang.Boolean> action);
method public static void setTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String p);
method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.AnnotatedString p);
method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString,java.lang.Boolean> action);
- method public static void setTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.TextRange p);
+ method public static void setTextSelectionRange-Hy0MoUY(androidx.compose.ui.semantics.SemanticsPropertyReceiver, long p);
+ method public static void setVerticalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityScrollState p);
}
public final class SemanticsPropertyKey<T> {
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index ed8a943..8a0333c 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -89,6 +89,16 @@
method public static int merge(androidx.compose.ui.AlignmentLine, int position1, int position2);
}
+ public final class CacheDrawScope implements androidx.compose.ui.unit.Density {
+ method public float getDensity();
+ method public float getFontScale();
+ method public long getSize();
+ method public androidx.compose.ui.DrawResult onDraw(kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+ property public float density;
+ property public float fontScale;
+ property public final long size;
+ }
+
public final class CombinedModifier implements androidx.compose.ui.Modifier {
ctor public CombinedModifier(androidx.compose.ui.Modifier outer, androidx.compose.ui.Modifier inner);
method public boolean all(kotlin.jvm.functions.Function1<? super androidx.compose.ui.Modifier.Element,java.lang.Boolean> predicate);
@@ -107,6 +117,10 @@
method public abstract void drawContent();
}
+ public interface DrawCacheModifier extends androidx.compose.ui.DrawModifier {
+ method public void onBuildCache-lwCvPpU(long size, androidx.compose.ui.unit.Density density);
+ }
+
public interface DrawLayerModifier extends androidx.compose.ui.Modifier.Element {
method @FloatRange(from=0.0, to=1.0) public default float getAlpha();
method public default boolean getClip();
@@ -145,9 +159,13 @@
public final class DrawModifierKt {
method public static androidx.compose.ui.Modifier drawBehind(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> onDraw);
+ method public static androidx.compose.ui.Modifier drawWithCache(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.CacheDrawScope,androidx.compose.ui.DrawResult> onBuildDrawCache);
method public static androidx.compose.ui.Modifier drawWithContent(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.ContentDrawScope,kotlin.Unit> onDraw);
}
+ public final class DrawResult {
+ }
+
public final class FocusModifierKt {
method @androidx.compose.runtime.Composable @androidx.compose.ui.focus.ExperimentalFocus public static androidx.compose.ui.Modifier focus(androidx.compose.ui.Modifier);
}
@@ -277,16 +295,16 @@
public abstract static class Placeable.PlacementScope {
ctor public Placeable.PlacementScope();
- method public abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
- method public abstract int getParentWidth();
+ method protected abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
+ method protected abstract int getParentWidth();
method public final void place(androidx.compose.ui.Placeable, int x, int y);
method public final void place-LmmdDA8(androidx.compose.ui.Placeable, long position);
method public final void place-gl1q84w(androidx.compose.ui.Placeable, long position);
method public final void placeRelative(androidx.compose.ui.Placeable, int x, int y);
method public final void placeRelative-LmmdDA8(androidx.compose.ui.Placeable, long position);
method public final void placeRelative-gl1q84w(androidx.compose.ui.Placeable, long position);
- property public abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
- property public abstract int parentWidth;
+ property protected abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
+ property protected abstract int parentWidth;
}
public interface Remeasurement {
@@ -451,15 +469,6 @@
@kotlin.RequiresOptIn(message="The Focus API is experimental and is likely to change in the future.") public @interface ExperimentalFocus {
}
- @androidx.compose.ui.focus.ExperimentalFocus public final class FocusManager {
- ctor public FocusManager();
- method public void clearFocus();
- method public androidx.compose.ui.Modifier getModifier();
- method public void releaseFocus();
- method public void takeFocus();
- property public final androidx.compose.ui.Modifier modifier;
- }
-
public final class FocusNodeUtilsKt {
}
@@ -1861,6 +1870,7 @@
method public void measureAndLayout();
method public void observeLayoutModelReads(androidx.compose.ui.node.LayoutNode node, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public void observeMeasureModelReads(androidx.compose.ui.node.LayoutNode node, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public <T> void observeReads(T target, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public void onAttach(androidx.compose.ui.node.LayoutNode node);
method public void onDetach(androidx.compose.ui.node.LayoutNode node);
method public void onRequestMeasure(androidx.compose.ui.node.LayoutNode layoutNode);
@@ -1961,14 +1971,12 @@
public interface AndroidOwner extends androidx.compose.ui.node.Owner {
method @androidx.compose.ui.node.ExperimentalLayoutNodeApi public void addAndroidView(android.view.View view, androidx.compose.ui.node.LayoutNode layoutNode);
method public kotlin.jvm.functions.Function1<android.content.res.Configuration,kotlin.Unit> getConfigurationChangeObserver();
- method public androidx.compose.ui.focus.FocusManager getFocusManager();
method public android.view.View getView();
method public androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners? getViewTreeOwners();
method public void removeAndroidView(android.view.View view);
method public void setConfigurationChangeObserver(kotlin.jvm.functions.Function1<? super android.content.res.Configuration,kotlin.Unit> p);
method public void setOnViewTreeOwnersAvailable(kotlin.jvm.functions.Function1<? super androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners,kotlin.Unit> callback);
property public abstract kotlin.jvm.functions.Function1<android.content.res.Configuration,kotlin.Unit> configurationChangeObserver;
- property public abstract androidx.compose.ui.focus.FocusManager focusManager;
property public abstract android.view.View view;
property public abstract androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners? viewTreeOwners;
}
@@ -2158,7 +2166,7 @@
method public boolean getHandlesCrossed();
method public androidx.compose.ui.selection.Selection.AnchorInfo getStart();
method public androidx.compose.ui.selection.Selection merge(androidx.compose.ui.selection.Selection? other);
- method public androidx.compose.ui.text.TextRange toTextRange();
+ method public long toTextRange();
}
@androidx.compose.runtime.Immutable public static final class Selection.AnchorInfo {
@@ -2219,6 +2227,18 @@
method public int getSteps();
}
+ public final class AccessibilityScrollState {
+ ctor public AccessibilityScrollState(float value, float maxValue, boolean reverseScrolling);
+ ctor public AccessibilityScrollState();
+ method public float component1();
+ method public float component2();
+ method public boolean component3();
+ method public androidx.compose.ui.semantics.AccessibilityScrollState copy(float value, float maxValue, boolean reverseScrolling);
+ method public float getMaxValue();
+ method public boolean getReverseScrolling();
+ method public float getValue();
+ }
+
public final class CustomAccessibilityAction {
ctor public CustomAccessibilityAction(CharSequence label, kotlin.jvm.functions.Function0<java.lang.Boolean> action);
method public CharSequence component1();
@@ -2327,22 +2347,26 @@
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getDisabled();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getFocused();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getHidden();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> getHorizontalAccessibilityScrollState();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsDialog();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsPopup();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> getTestTag();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> getText();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.TextRange> getTextSelectionRange();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> getVerticalAccessibilityScrollState();
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> AccessibilityLabel;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityRangeInfo> AccessibilityRangeInfo;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> AccessibilityValue;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Disabled;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> Focused;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Hidden;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> HorizontalAccessibilityScrollState;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsDialog;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsPopup;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> TestTag;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> Text;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.TextRange> TextSelectionRange;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> VerticalAccessibilityScrollState;
field public static final androidx.compose.ui.semantics.SemanticsProperties INSTANCE;
}
@@ -2354,10 +2378,12 @@
method public static androidx.compose.ui.semantics.AccessibilityRangeInfo getAccessibilityValueRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction> getCustomActions(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static boolean getFocused(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static androidx.compose.ui.semantics.AccessibilityScrollState getHorizontalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static String getTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static androidx.compose.ui.text.AnnotatedString getText(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void getTextLayoutResult(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.ui.text.TextLayoutResult>,java.lang.Boolean> action);
- method public static androidx.compose.ui.text.TextRange getTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static long getTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static androidx.compose.ui.semantics.AccessibilityScrollState getVerticalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void hidden(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void onClick(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function0<java.lang.Boolean> action);
method public static void popup(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
@@ -2367,12 +2393,14 @@
method public static void setAccessibilityValueRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityRangeInfo p);
method public static void setCustomActions(androidx.compose.ui.semantics.SemanticsPropertyReceiver, java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction> p);
method public static void setFocused(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean p);
+ method public static void setHorizontalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityScrollState p);
method public static void setProgress(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Boolean> action);
method public static void setSelection(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Boolean,java.lang.Boolean> action);
method public static void setTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String p);
method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.AnnotatedString p);
method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString,java.lang.Boolean> action);
- method public static void setTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.TextRange p);
+ method public static void setTextSelectionRange-Hy0MoUY(androidx.compose.ui.semantics.SemanticsPropertyReceiver, long p);
+ method public static void setVerticalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityScrollState p);
}
public final class SemanticsPropertyKey<T> {
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index 61a9cb3..965c52d 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -89,6 +89,16 @@
method public static int merge(androidx.compose.ui.AlignmentLine, int position1, int position2);
}
+ public final class CacheDrawScope implements androidx.compose.ui.unit.Density {
+ method public float getDensity();
+ method public float getFontScale();
+ method public long getSize();
+ method public androidx.compose.ui.DrawResult onDraw(kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+ property public float density;
+ property public float fontScale;
+ property public final long size;
+ }
+
public final class CombinedModifier implements androidx.compose.ui.Modifier {
ctor public CombinedModifier(androidx.compose.ui.Modifier outer, androidx.compose.ui.Modifier inner);
method public boolean all(kotlin.jvm.functions.Function1<? super androidx.compose.ui.Modifier.Element,java.lang.Boolean> predicate);
@@ -121,6 +131,10 @@
property public Object? parentData;
}
+ public interface DrawCacheModifier extends androidx.compose.ui.DrawModifier {
+ method public void onBuildCache-lwCvPpU(long size, androidx.compose.ui.unit.Density density);
+ }
+
public interface DrawLayerModifier extends androidx.compose.ui.Modifier.Element {
method @FloatRange(from=0.0, to=1.0) public default float getAlpha();
method public default boolean getClip();
@@ -159,9 +173,13 @@
public final class DrawModifierKt {
method public static androidx.compose.ui.Modifier drawBehind(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> onDraw);
+ method public static androidx.compose.ui.Modifier drawWithCache(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.CacheDrawScope,androidx.compose.ui.DrawResult> onBuildDrawCache);
method public static androidx.compose.ui.Modifier drawWithContent(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.ContentDrawScope,kotlin.Unit> onDraw);
}
+ public final class DrawResult {
+ }
+
public final class FocusModifierKt {
method @androidx.compose.runtime.Composable @androidx.compose.ui.focus.ExperimentalFocus public static androidx.compose.ui.Modifier focus(androidx.compose.ui.Modifier);
}
@@ -324,16 +342,16 @@
public abstract static class Placeable.PlacementScope {
ctor public Placeable.PlacementScope();
- method public abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
- method public abstract int getParentWidth();
+ method protected abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
+ method protected abstract int getParentWidth();
method public final void place(androidx.compose.ui.Placeable, int x, int y);
method public final void place-LmmdDA8(androidx.compose.ui.Placeable, long position);
method public final void place-gl1q84w(androidx.compose.ui.Placeable, long position);
method public final void placeRelative(androidx.compose.ui.Placeable, int x, int y);
method public final void placeRelative-LmmdDA8(androidx.compose.ui.Placeable, long position);
method public final void placeRelative-gl1q84w(androidx.compose.ui.Placeable, long position);
- property public abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
- property public abstract int parentWidth;
+ property protected abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
+ property protected abstract int parentWidth;
}
public interface Remeasurement {
@@ -498,15 +516,6 @@
@kotlin.RequiresOptIn(message="The Focus API is experimental and is likely to change in the future.") public @interface ExperimentalFocus {
}
- @androidx.compose.ui.focus.ExperimentalFocus public final class FocusManager {
- ctor public FocusManager();
- method public void clearFocus();
- method public androidx.compose.ui.Modifier getModifier();
- method public void releaseFocus();
- method public void takeFocus();
- property public final androidx.compose.ui.Modifier modifier;
- }
-
public final class FocusNodeUtilsKt {
}
@@ -1923,6 +1932,7 @@
method public void measureAndLayout();
method public void observeLayoutModelReads(androidx.compose.ui.node.LayoutNode node, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public void observeMeasureModelReads(androidx.compose.ui.node.LayoutNode node, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public <T> void observeReads(T target, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public void onAttach(androidx.compose.ui.node.LayoutNode node);
method public void onDetach(androidx.compose.ui.node.LayoutNode node);
method public void onRequestMeasure(androidx.compose.ui.node.LayoutNode layoutNode);
@@ -2032,14 +2042,12 @@
public interface AndroidOwner extends androidx.compose.ui.node.Owner {
method @androidx.compose.ui.node.ExperimentalLayoutNodeApi public void addAndroidView(android.view.View view, androidx.compose.ui.node.LayoutNode layoutNode);
method public kotlin.jvm.functions.Function1<android.content.res.Configuration,kotlin.Unit> getConfigurationChangeObserver();
- method public androidx.compose.ui.focus.FocusManager getFocusManager();
method public android.view.View getView();
method public androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners? getViewTreeOwners();
method public void removeAndroidView(android.view.View view);
method public void setConfigurationChangeObserver(kotlin.jvm.functions.Function1<? super android.content.res.Configuration,kotlin.Unit> p);
method public void setOnViewTreeOwnersAvailable(kotlin.jvm.functions.Function1<? super androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners,kotlin.Unit> callback);
property public abstract kotlin.jvm.functions.Function1<android.content.res.Configuration,kotlin.Unit> configurationChangeObserver;
- property public abstract androidx.compose.ui.focus.FocusManager focusManager;
property public abstract android.view.View view;
property public abstract androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners? viewTreeOwners;
}
@@ -2235,7 +2243,7 @@
method public boolean getHandlesCrossed();
method public androidx.compose.ui.selection.Selection.AnchorInfo getStart();
method public androidx.compose.ui.selection.Selection merge(androidx.compose.ui.selection.Selection? other);
- method public androidx.compose.ui.text.TextRange toTextRange();
+ method public long toTextRange();
}
@androidx.compose.runtime.Immutable public static final class Selection.AnchorInfo {
@@ -2296,6 +2304,18 @@
method public int getSteps();
}
+ public final class AccessibilityScrollState {
+ ctor public AccessibilityScrollState(float value, float maxValue, boolean reverseScrolling);
+ ctor public AccessibilityScrollState();
+ method public float component1();
+ method public float component2();
+ method public boolean component3();
+ method public androidx.compose.ui.semantics.AccessibilityScrollState copy(float value, float maxValue, boolean reverseScrolling);
+ method public float getMaxValue();
+ method public boolean getReverseScrolling();
+ method public float getValue();
+ }
+
public final class CustomAccessibilityAction {
ctor public CustomAccessibilityAction(CharSequence label, kotlin.jvm.functions.Function0<java.lang.Boolean> action);
method public CharSequence component1();
@@ -2404,22 +2424,26 @@
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getDisabled();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getFocused();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getHidden();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> getHorizontalAccessibilityScrollState();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsDialog();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsPopup();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> getTestTag();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> getText();
method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.TextRange> getTextSelectionRange();
+ method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> getVerticalAccessibilityScrollState();
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> AccessibilityLabel;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityRangeInfo> AccessibilityRangeInfo;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> AccessibilityValue;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Disabled;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> Focused;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Hidden;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> HorizontalAccessibilityScrollState;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsDialog;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsPopup;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> TestTag;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> Text;
property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.TextRange> TextSelectionRange;
+ property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> VerticalAccessibilityScrollState;
field public static final androidx.compose.ui.semantics.SemanticsProperties INSTANCE;
}
@@ -2431,10 +2455,12 @@
method public static androidx.compose.ui.semantics.AccessibilityRangeInfo getAccessibilityValueRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction> getCustomActions(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static boolean getFocused(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static androidx.compose.ui.semantics.AccessibilityScrollState getHorizontalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static String getTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static androidx.compose.ui.text.AnnotatedString getText(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void getTextLayoutResult(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.ui.text.TextLayoutResult>,java.lang.Boolean> action);
- method public static androidx.compose.ui.text.TextRange getTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static long getTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+ method public static androidx.compose.ui.semantics.AccessibilityScrollState getVerticalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void hidden(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
method public static void onClick(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function0<java.lang.Boolean> action);
method public static void popup(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
@@ -2444,12 +2470,14 @@
method public static void setAccessibilityValueRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityRangeInfo p);
method public static void setCustomActions(androidx.compose.ui.semantics.SemanticsPropertyReceiver, java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction> p);
method public static void setFocused(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean p);
+ method public static void setHorizontalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityScrollState p);
method public static void setProgress(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Boolean> action);
method public static void setSelection(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Boolean,java.lang.Boolean> action);
method public static void setTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String p);
method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.AnnotatedString p);
method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString,java.lang.Boolean> action);
- method public static void setTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.TextRange p);
+ method public static void setTextSelectionRange-Hy0MoUY(androidx.compose.ui.semantics.SemanticsPropertyReceiver, long p);
+ method public static void setVerticalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityScrollState p);
}
public final class SemanticsPropertyKey<T> {
diff --git a/compose/ui/ui/build.gradle b/compose/ui/ui/build.gradle
index 232a3c7..9f3e123 100644
--- a/compose/ui/ui/build.gradle
+++ b/compose/ui/ui/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/compose/ui/ui/integration-tests/ui-demos/build.gradle b/compose/ui/ui/integration-tests/ui-demos/build.gradle
index 3fdea37..962cd5a 100644
--- a/compose/ui/ui/integration-tests/ui-demos/build.gradle
+++ b/compose/ui/ui/integration-tests/ui-demos/build.gradle
@@ -10,7 +10,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/ui/ui/samples/build.gradle b/compose/ui/ui/samples/build.gradle
index 143aac3..f524a13 100644
--- a/compose/ui/ui/samples/build.gradle
+++ b/compose/ui/ui/samples/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/DrawModifierSample.kt b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/DrawModifierSample.kt
new file mode 100644
index 0000000..ba574c0
--- /dev/null
+++ b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/DrawModifierSample.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020 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 androidx.compose.ui.samples
+
+import androidx.annotation.Sampled
+import androidx.compose.foundation.Box
+import androidx.compose.foundation.clickable
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.drawWithCache
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.LinearGradient
+
+/**
+ * Sample showing how to leverage [Modifier.drawWithCache] in order
+ * to cache contents in between draw calls that depend on sizing information.
+ * In the example below, the LinearGradient is created once and re-used across
+ * calls to onDraw. If the size of the drawing area changes, then the
+ * LinearGradient is re-created with the updated width and height.
+ */
+@Sampled
+@Composable
+fun DrawWithCacheModifierSample() {
+ Box(
+ Modifier.drawWithCache {
+ val gradient = LinearGradient(
+ startX = 0.0f,
+ startY = 0.0f,
+ endX = size.width,
+ endY = size.height,
+ colors = listOf(Color.Red, Color.Blue)
+ )
+ onDraw {
+ drawRect(gradient)
+ }
+ }
+ )
+}
+
+/**
+ * Sample showing how to leverage [Modifier.drawWithCache] to persist data across
+ * draw calls. In the example below, the [LinearGradient] will be re-created if either
+ * the size of the drawing area changes, or the toggle flag represented by a mutable state
+ * object changes. Otherwise the same [LinearGradient] instance is re-used for each call
+ * to drawRect.
+ */
+@Sampled
+@Composable
+fun DrawWithCacheModifierStateParameterSample() {
+ val colors1 = listOf(Color.Red, Color.Blue)
+ val colors2 = listOf(Color.Yellow, Color.Green)
+ var toggle by remember { mutableStateOf(true) }
+ Box(
+ Modifier.clickable { toggle = !toggle }.drawWithCache {
+ val gradient = LinearGradient(
+ startX = 0.0f,
+ startY = 0.0f,
+ endX = size.width,
+ endY = size.height,
+ colors = if (toggle) colors1 else colors2
+ )
+ onDraw {
+ drawRect(gradient)
+ }
+ }
+ )
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
index 3738bb5..dfd0dc9 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
@@ -283,7 +283,8 @@
.getParcelableArray(AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY)
assertEquals(1, data!!.size)
val rectF = data[0] as RectF
- val expectedRect = textLayoutResult.getBoundingBox(0).shift(textFieldNode.globalPosition)
+ val expectedRect = textLayoutResult.getBoundingBox(0).translate(textFieldNode
+ .globalPosition)
assertEquals(expectedRect.left, rectF.left)
assertEquals(expectedRect.top, rectF.top)
assertEquals(expectedRect.right, rectF.right)
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt
new file mode 100644
index 0000000..857768b
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2020 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 androidx.compose.ui.draw
+
+import android.os.Build
+import androidx.compose.foundation.clickable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.AtLeastSize
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.drawWithCache
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.testTag
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.ui.test.captureToBitmap
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.onNodeWithTag
+import androidx.ui.test.performClick
+import org.junit.Assert.assertEquals
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@MediumTest
+@RunWith(JUnit4::class)
+class DrawModifierTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun testCacheHitWithStateChange() {
+ // Verify that a state change outside of the cache block does not
+ // require the cache block to be invalidated
+ val testTag = "testTag"
+ var cacheBuildCount = 0
+ val size = 200
+ rule.setContent {
+ var rectColor by remember { mutableStateOf(Color.Blue) }
+ AtLeastSize(size = size, modifier = Modifier.testTag(testTag).drawWithCache {
+ val drawSize = this.size
+ val path = Path().apply {
+ lineTo(drawSize.width / 2f, 0f)
+ lineTo(drawSize.width / 2f, drawSize.height)
+ lineTo(0f, drawSize.height)
+ close()
+ }
+ cacheBuildCount++
+ onDraw {
+ drawRect(rectColor)
+ drawPath(path, Color.Red)
+ }
+ }.clickable {
+ if (rectColor == Color.Blue) {
+ rectColor = Color.Green
+ } else {
+ rectColor = Color.Blue
+ }
+ }) { }
+ }
+
+ rule.onNodeWithTag(testTag).apply {
+ // Verify that the path was created only once
+ assertEquals(1, cacheBuildCount)
+ captureToBitmap().apply {
+ assertEquals(Color.Red.toArgb(), getPixel(1, 1))
+ assertEquals(Color.Red.toArgb(), getPixel(width / 2 - 2, 1))
+ assertEquals(Color.Red.toArgb(), getPixel(width / 2 - 2, height / 2 - 2))
+ assertEquals(Color.Red.toArgb(), getPixel(1, height / 2 - 2))
+
+ assertEquals(Color.Blue.toArgb(), getPixel(width / 2 + 1, 1))
+ assertEquals(Color.Blue.toArgb(), getPixel(width - 2, 1))
+ assertEquals(Color.Blue.toArgb(), getPixel(width / 2 + 1, height - 2))
+ assertEquals(Color.Blue.toArgb(), getPixel(width - 2, height - 2))
+ }
+ performClick()
+ }
+
+ rule.waitForIdle()
+
+ rule.onNodeWithTag(testTag).apply {
+ // Verify that the path was re-used and only built once
+ assertEquals(1, cacheBuildCount)
+ captureToBitmap().apply {
+ assertEquals(Color.Red.toArgb(), getPixel(1, 1))
+ assertEquals(Color.Red.toArgb(), getPixel(width / 2 - 2, 1))
+ assertEquals(Color.Red.toArgb(), getPixel(width / 2 - 2, height / 2 - 1))
+ assertEquals(Color.Red.toArgb(), getPixel(1, height / 2 - 2))
+
+ assertEquals(Color.Green.toArgb(), getPixel(width / 2 + 1, 1))
+ assertEquals(Color.Green.toArgb(), getPixel(width - 2, 1))
+ assertEquals(Color.Green.toArgb(), getPixel(width / 2 + 1, height - 2))
+ assertEquals(Color.Green.toArgb(), getPixel(width - 2, height - 2))
+ }
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun testCacheInvalidatedAfterStateChange() {
+ // Verify that a state change within the cache block does
+ // require the cache block to be invalidated
+ val testTag = "testTag"
+ var cacheBuildCount = 0
+ val size = 200
+
+ rule.setContent {
+ var pathFillBounds by remember { mutableStateOf(false) }
+ AtLeastSize(size = size, modifier = Modifier.testTag(testTag).drawWithCache {
+ val pathSize = if (pathFillBounds) this.size else this.size / 2f
+ val path = Path().apply {
+ lineTo(pathSize.width, 0f)
+ lineTo(pathSize.width, pathSize.height)
+ lineTo(0f, pathSize.height)
+ close()
+ }
+ cacheBuildCount++
+ onDraw {
+ drawRect(Color.Red)
+ drawPath(path, Color.Blue)
+ }
+ }.clickable {
+ pathFillBounds = !pathFillBounds
+ }) { }
+ }
+
+ rule.onNodeWithTag(testTag).apply {
+ // Verify that the path was created only once
+ assertEquals(1, cacheBuildCount)
+ captureToBitmap().apply {
+ assertEquals(Color.Blue.toArgb(), getPixel(1, 1))
+ assertEquals(Color.Blue.toArgb(), getPixel(width / 2 - 2, 1))
+ assertEquals(Color.Blue.toArgb(), getPixel(width / 2 - 2, height / 2 - 2))
+ assertEquals(Color.Blue.toArgb(), getPixel(1, height / 2 - 1))
+
+ assertEquals(Color.Red.toArgb(), getPixel(width / 2 + 1, 1))
+ assertEquals(Color.Red.toArgb(), getPixel(width / 2 + 1, height / 2 - 1))
+ assertEquals(Color.Red.toArgb(), getPixel(width / 2 + 1, height / 2 - 2))
+ assertEquals(Color.Red.toArgb(), getPixel(width / 2 - 2, height / 2 + 1))
+ assertEquals(Color.Red.toArgb(), getPixel(1, height / 2 + 1))
+
+ assertEquals(Color.Red.toArgb(), getPixel(1, height - 2))
+ assertEquals(Color.Red.toArgb(), getPixel(width - 2, 1))
+ assertEquals(Color.Red.toArgb(), getPixel(width - 2, height - 2))
+ }
+ performClick()
+ }
+
+ rule.waitForIdle()
+
+ rule.onNodeWithTag(testTag).apply {
+ assertEquals(2, cacheBuildCount)
+ captureToBitmap().apply {
+ assertEquals(Color.Blue.toArgb(), getPixel(1, 1))
+ assertEquals(Color.Blue.toArgb(), getPixel(size - 2, 1))
+ assertEquals(Color.Blue.toArgb(), getPixel(size - 2, size - 2))
+ assertEquals(Color.Blue.toArgb(), getPixel(1, size - 2))
+ }
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun testCacheInvalidatedAfterSizeChange() {
+ // Verify that a size change does cause the cache block to be invalidated
+ val testTag = "testTag"
+ var cacheBuildCount = 0
+ val startSize = 200
+ val endSize = 400
+ rule.setContent {
+ var size by remember { mutableStateOf(startSize) }
+ AtLeastSize(size = size, modifier = Modifier.testTag(testTag).drawWithCache {
+ val drawSize = this.size
+ val path = Path().apply {
+ lineTo(drawSize.width, 0f)
+ lineTo(drawSize.height, drawSize.height)
+ lineTo(0f, drawSize.height)
+ close()
+ }
+ cacheBuildCount++
+ onDraw {
+ drawPath(path, Color.Red)
+ }
+ }.clickable {
+ if (size == startSize) {
+ size = endSize
+ } else {
+ size = startSize
+ }
+ }) { }
+ }
+
+ rule.onNodeWithTag(testTag).apply {
+ // Verify that the path was created only once
+ assertEquals(1, cacheBuildCount)
+ captureToBitmap().apply {
+ assertEquals(startSize, this.width)
+ assertEquals(startSize, this.height)
+ assertEquals(Color.Red.toArgb(), getPixel(1, 1))
+ assertEquals(Color.Red.toArgb(), getPixel(width - 2, height - 2))
+ }
+ performClick()
+ }
+
+ rule.waitForIdle()
+
+ rule.onNodeWithTag(testTag).apply {
+ // Verify that the path was re-used and only built once
+ assertEquals(2, cacheBuildCount)
+ captureToBitmap().apply {
+ assertEquals(endSize, this.width)
+ assertEquals(endSize, this.height)
+ assertEquals(Color.Red.toArgb(), getPixel(1, 1))
+ assertEquals(Color.Red.toArgb(), getPixel(width - 2, height - 2))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/SetRootFocus.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/SetRootFocusTest.kt
similarity index 98%
rename from compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/SetRootFocus.kt
rename to compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/SetRootFocusTest.kt
index a575b6d..e6ef28a 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/SetRootFocus.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/SetRootFocusTest.kt
@@ -37,7 +37,7 @@
@MediumTest
@OptIn(ExperimentalFocus::class)
@RunWith(JUnit4::class)
-class SetRootFocus {
+class SetRootFocusTest {
@get:Rule
val rule = createComposeRule()
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
index ce7dd7d..a273e56 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
@@ -3026,6 +3026,10 @@
block()
}
+ override fun <T : Any> observeReads(target: T, onChanged: (T) -> Unit, block: () -> Unit) {
+ block()
+ }
+
override fun measureAndLayout() {
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/node/ViewInterop.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/node/ViewInterop.kt
index 8f45579..4514404 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/node/ViewInterop.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/node/ViewInterop.kt
@@ -23,7 +23,7 @@
import androidx.compose.ui.MeasureScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.drawBehind
-import androidx.compose.ui.graphics.drawscope.drawCanvas
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.layout.positionInRoot
@@ -104,7 +104,7 @@
val coreModifier = Modifier
.pointerInteropFilter(this)
.drawBehind {
- drawCanvas { canvas, _ -> draw(canvas.nativeCanvas) }
+ drawIntoCanvas { canvas -> draw(canvas.nativeCanvas) }
}.onPositioned {
// The global position of this LayoutNode can change with it being replaced. For these
// cases, we need to inform the View.
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.kt
index ad73d7d..e2c9d5b 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.kt
@@ -138,7 +138,7 @@
properties = {}
)
- override val focusManager: FocusManager = FocusManager()
+ private val focusManager: FocusManager = FocusManager()
private val keyInputModifier = KeyInputModifier(null, null)
@@ -417,6 +417,10 @@
snapshotObserver.observeReads(node, onCommitAffectingMeasure, block)
}
+ override fun <T : Any> observeReads(target: T, onChanged: (T) -> Unit, block: () -> Unit) {
+ snapshotObserver.observeReads(target, onChanged, block)
+ }
+
fun observeLayerModelReads(layer: OwnedLayer, block: () -> Unit) {
snapshotObserver.observeReads(layer, onCommitAffectingLayer, block)
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.kt
index 14e0111..3d9e722 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.kt
@@ -34,6 +34,7 @@
import android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
import android.view.accessibility.AccessibilityNodeProvider
import androidx.annotation.IntRange
+import androidx.annotation.RequiresApi
import androidx.collection.SparseArrayCompat
import androidx.compose.ui.R
import androidx.compose.ui.geometry.Rect
@@ -283,7 +284,9 @@
if (rangeInfo != null) {
info.rangeInfo = AccessibilityNodeInfoCompat.RangeInfoCompat.obtain(
AccessibilityNodeInfoCompat.RangeInfoCompat.RANGE_TYPE_FLOAT,
- rangeInfo.range.start, rangeInfo.range.endInclusive, rangeInfo.current
+ rangeInfo.range.start,
+ rangeInfo.range.endInclusive,
+ rangeInfo.current
)
if (semanticsNode.config.contains(SemanticsActions.SetProgress)) {
if (rangeInfo.current <
@@ -299,6 +302,78 @@
}
}
+ val xScrollState =
+ semanticsNode.config.getOrNull(SemanticsProperties.HorizontalAccessibilityScrollState)
+ val scrollAction = semanticsNode.config.getOrNull(SemanticsActions.ScrollBy)
+ if (xScrollState != null && scrollAction != null) {
+ // Talkback defines SCROLLABLE_ROLE_FILTER_FOR_DIRECTION_NAVIGATION, so we need to
+ // assign a role for auto scroll to work.
+ info.className = "android.widget.HorizontalScrollView"
+ if (xScrollState.value < xScrollState.maxValue) {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_FORWARD
+ )
+ if (!xScrollState.reverseScrolling) {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT
+ )
+ } else {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT
+ )
+ }
+ }
+ if (xScrollState.value > 0f) {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_BACKWARD
+ )
+ if (!xScrollState.reverseScrolling) {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT
+ )
+ } else {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT
+ )
+ }
+ }
+ }
+ val yScrollState =
+ semanticsNode.config.getOrNull(SemanticsProperties.VerticalAccessibilityScrollState)
+ if (yScrollState != null && scrollAction != null) {
+ // Talkback defines SCROLLABLE_ROLE_FILTER_FOR_DIRECTION_NAVIGATION, so we need to
+ // assign a role for auto scroll to work.
+ info.className = "android.widget.ScrollView"
+ if (yScrollState.value < yScrollState.maxValue) {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_FORWARD
+ )
+ if (!yScrollState.reverseScrolling) {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN
+ )
+ } else {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP
+ )
+ }
+ }
+ if (yScrollState.value > 0f) {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_BACKWARD
+ )
+ if (!yScrollState.reverseScrolling) {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP
+ )
+ } else {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN
+ )
+ }
+ }
+ }
+
if (semanticsNode.config.contains(CustomActions)) {
val customActions = semanticsNode.config[CustomActions]
if (customActions.size >= AccessibilityActionsResourceIds.size) {
@@ -540,21 +615,87 @@
}
}
AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD,
- AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD -> {
- val rangeInfo = node.config.getOrNull(SemanticsProperties.AccessibilityRangeInfo)
- val setProgressAction = node.config.getOrNull(SemanticsActions.SetProgress)
- if (rangeInfo != null && setProgressAction != null) {
- val max = rangeInfo.range.endInclusive.coerceAtLeast(rangeInfo.range.start)
- val min = rangeInfo.range.start.coerceAtMost(rangeInfo.range.endInclusive)
- var increment = if (rangeInfo.steps > 0) {
- (max - min) / (rangeInfo.steps + 1)
- } else {
- (max - min) / AccessibilitySliderStepsCount
+ AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD,
+ android.R.id.accessibilityActionScrollDown,
+ android.R.id.accessibilityActionScrollUp,
+ android.R.id.accessibilityActionScrollRight,
+ android.R.id.accessibilityActionScrollLeft -> {
+ if (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD ||
+ action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD) {
+ val rangeInfo =
+ node.config.getOrNull(SemanticsProperties.AccessibilityRangeInfo)
+ val setProgressAction = node.config.getOrNull(SemanticsActions.SetProgress)
+ if (rangeInfo != null && setProgressAction != null) {
+ val max = rangeInfo.range.endInclusive.coerceAtLeast(rangeInfo.range.start)
+ val min = rangeInfo.range.start.coerceAtMost(rangeInfo.range.endInclusive)
+ var increment = if (rangeInfo.steps > 0) {
+ (max - min) / (rangeInfo.steps + 1)
+ } else {
+ (max - min) / AccessibilitySliderStepsCount
+ }
+ if (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD) {
+ increment = -increment
+ }
+ return setProgressAction.action(rangeInfo.current + increment)
}
- if (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD) {
- increment = -increment
+ }
+
+ val scrollAction = node.config.getOrNull(SemanticsActions.ScrollBy) ?: return false
+ val xScrollState =
+ node.config.getOrNull(SemanticsProperties.HorizontalAccessibilityScrollState)
+ if (xScrollState != null) {
+ if (((!xScrollState.reverseScrolling &&
+ action == android.R.id.accessibilityActionScrollRight) ||
+ (xScrollState.reverseScrolling &&
+ action == android.R.id.accessibilityActionScrollLeft) ||
+ (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD)) &&
+ xScrollState.value < xScrollState.maxValue
+ ) {
+ return scrollAction.action(
+ node.globalBounds.right - node.globalBounds.left,
+ 0f
+ )
}
- return setProgressAction.action(rangeInfo.current + increment)
+ if (((xScrollState.reverseScrolling &&
+ action == android.R.id.accessibilityActionScrollRight) ||
+ (!xScrollState.reverseScrolling &&
+ action == android.R.id.accessibilityActionScrollLeft) ||
+ (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD)) &&
+ xScrollState.value > 0
+ ) {
+ return scrollAction.action(
+ -(node.globalBounds.right - node.globalBounds.left),
+ 0f
+ )
+ }
+ }
+ val yScrollState =
+ node.config.getOrNull(SemanticsProperties.VerticalAccessibilityScrollState)
+ if (yScrollState != null) {
+ if (((!yScrollState.reverseScrolling &&
+ action == android.R.id.accessibilityActionScrollDown) ||
+ (yScrollState.reverseScrolling &&
+ action == android.R.id.accessibilityActionScrollUp) ||
+ (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD)) &&
+ yScrollState.value < yScrollState.maxValue
+ ) {
+ return scrollAction.action(
+ 0f,
+ node.globalBounds.bottom - node.globalBounds.top
+ )
+ }
+ if (((yScrollState.reverseScrolling &&
+ action == android.R.id.accessibilityActionScrollDown) ||
+ (!yScrollState.reverseScrolling &&
+ action == android.R.id.accessibilityActionScrollUp) ||
+ (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD)) &&
+ yScrollState.value > 0
+ ) {
+ return scrollAction.action(
+ 0f,
+ -(node.globalBounds.bottom - node.globalBounds.top)
+ )
+ }
}
return false
}
@@ -683,7 +824,7 @@
}
private fun toScreenCoords(textNode: SemanticsNode, bounds: Rect): Rect? {
- val screenBounds = bounds.shift(textNode.globalPosition)
+ val screenBounds = bounds.translate(textNode.globalPosition)
val globalBounds = textNode.globalBounds
if (screenBounds.overlaps(globalBounds)) {
return screenBounds.intersect(globalBounds)
@@ -945,7 +1086,8 @@
SemanticsProperties.Text) { AnnotatedString("") }).text
val event = createEvent(
semanticsNodeIdToAccessibilityVirtualNodeId(id),
- AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED)
+ AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
+ )
val textRange = newNode.config[SemanticsProperties.TextSelectionRange]
event.fromIndex = textRange.start
event.toIndex = textRange.end
@@ -953,6 +1095,56 @@
event.text.add(trimToSize(newText, ParcelSafeTextLength))
sendEvent(event)
}
+ SemanticsProperties.HorizontalAccessibilityScrollState,
+ SemanticsProperties.VerticalAccessibilityScrollState -> {
+ // TODO(yingleiw): Add throttling for scroll/state events.
+ val newXState = newNode.config.getOrNull(
+ SemanticsProperties.HorizontalAccessibilityScrollState
+ )
+ val oldXState = oldNode.config.getOrNull(
+ SemanticsProperties.HorizontalAccessibilityScrollState
+ )
+ val newYState = newNode.config.getOrNull(
+ SemanticsProperties.VerticalAccessibilityScrollState
+ )
+ val oldYState = oldNode.config.getOrNull(
+ SemanticsProperties.VerticalAccessibilityScrollState
+ )
+ sendEventForVirtualView(
+ semanticsNodeIdToAccessibilityVirtualNodeId(newNode.id),
+ AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED,
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE,
+ null
+ )
+ val deltaX = if (newXState != null && oldXState != null) {
+ newXState.value - oldXState.value
+ } else {
+ 0
+ }
+ val deltaY = if (newYState != null && oldYState != null) {
+ newYState.value - oldYState.value
+ } else {
+ 0
+ }
+ if (deltaX != 0f || deltaY != 0f) {
+ val event = createEvent(
+ semanticsNodeIdToAccessibilityVirtualNodeId(id),
+ AccessibilityEvent.TYPE_VIEW_SCROLLED
+ )
+ if (newXState != null) {
+ event.scrollX = newXState.value.toInt()
+ event.maxScrollX = newXState.maxValue.toInt()
+ }
+ if (newYState != null) {
+ event.scrollY = newYState.value.toInt()
+ event.maxScrollY = newYState.maxValue.toInt()
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ Api28Impl.setScrollEventDelta(event, deltaX.toInt(), deltaY.toInt())
+ }
+ sendEvent(event)
+ }
+ }
else -> {
// TODO(b/151840490) send the correct events when property changes
}
@@ -1214,4 +1406,14 @@
addExtraDataToAccessibilityNodeInfoHelper(virtualViewId, info, extraDataKey, arguments)
}
}
+
+ private class Api28Impl {
+ @RequiresApi(Build.VERSION_CODES.P)
+ companion object {
+ fun setScrollEventDelta(event: AccessibilityEvent, deltaX: Int, deltaY: Int) {
+ event.scrollDeltaX = deltaX
+ event.scrollDeltaY = deltaY
+ }
+ }
+ }
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidOwner.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidOwner.kt
index 03f1663..d975333 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidOwner.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidOwner.kt
@@ -18,8 +18,6 @@
import android.content.res.Configuration
import android.view.View
import androidx.annotation.RestrictTo
-import androidx.compose.ui.focus.ExperimentalFocus
-import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.node.ExperimentalLayoutNodeApi
import androidx.compose.ui.node.LayoutNode
import androidx.compose.ui.node.Owner
@@ -39,12 +37,6 @@
val view: View
/**
- * Provide a focus manager that controls focus within Compose.
- */
- @ExperimentalFocus
- val focusManager: FocusManager
-
- /**
* Called to inform the owner that a new Android [View] was [attached][Owner.onAttach]
* to the hierarchy.
*/
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
index c8c34d2..f6d8294 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
@@ -35,11 +35,7 @@
import androidx.compose.runtime.currentComposer
import androidx.compose.runtime.emptyContent
import androidx.compose.runtime.tooling.InspectionTables
-import androidx.compose.ui.Layout
-import androidx.compose.ui.Modifier
import androidx.compose.ui.R
-import androidx.compose.ui.focus.ExperimentalFocus
-import androidx.compose.ui.gesture.noConsumptionTapGestureFilter
import androidx.compose.ui.node.ExperimentalLayoutNodeApi
import androidx.compose.ui.node.LayoutNode
import androidx.compose.ui.node.UiApplier
@@ -48,7 +44,6 @@
import androidx.lifecycle.LifecycleOwner
import java.util.Collections
import java.util.WeakHashMap
-import kotlin.math.max
/**
* Composes the children of the view with the passed in [composable].
@@ -267,21 +262,9 @@
val inspectionTable =
owner.view.getTag(R.id.inspection_slot_table_set) as?
MutableSet<SlotTable>
- if (inspectionTable != null) {
- inspectionTable.add(currentComposer.slotTable)
- }
+ inspectionTable?.add(currentComposer.slotTable)
Providers(InspectionTables provides inspectionTable) {
- ProvideAndroidAmbients(owner) {
- // TODO(ralu): Please move the modifier to the root layout and
- // remove the [simpleLayout].
- simpleLayout(
- modifier = Modifier.noConsumptionTapGestureFilter {
- @OptIn(ExperimentalFocus::class)
- owner.focusManager.clearFocus()
- },
- children = content
- )
- }
+ ProvideAndroidAmbients(owner, content)
}
}
} else {
@@ -312,29 +295,6 @@
}
}
-@Composable
-private fun simpleLayout(modifier: Modifier = Modifier, children: @Composable () -> Unit) {
- Layout(modifier = modifier, children = children) { measurables, constraints ->
- val placeables = measurables.map { measurable ->
- measurable.measure(constraints)
- }
-
- val width = placeables.fold(0) { maxWidth, placeable ->
- max(maxWidth, (placeable.width))
- }
-
- val height = placeables.fold(0) { minWidth, placeable ->
- max(minWidth, (placeable.height))
- }
-
- layout(width, height) {
- placeables.forEach { placeable ->
- placeable.place(0, 0)
- }
- }
- }
-}
-
private val DefaultLayoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/DrawModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/DrawModifier.kt
index c643423..81f7ec1 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/DrawModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/DrawModifier.kt
@@ -16,17 +16,41 @@
package androidx.compose.ui
+import androidx.compose.runtime.remember
+import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Canvas
import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.unit.Density
/**
* A [Modifier.Element] that draws into the space of the layout.
*/
interface DrawModifier : Modifier.Element {
+
fun ContentDrawScope.draw()
}
/**
+ * [DrawModifier] implementation that supports building a cache of objects
+ * to be referenced across draw calls
+ */
+interface DrawCacheModifier : DrawModifier {
+
+ /**
+ * Callback invoked to re-build objects to be re-used across draw calls.
+ * This is useful to conditionally recreate objects only if the size of the
+ * drawing environment changes, or if state parameters that are inputs
+ * to objects change. This method is guaranteed to be called before
+ * [DrawModifier.draw].
+ *
+ * @param size The current size of the drawing environment
+ * @param density The current screen density to provide the ability to convert between
+ * density independent and raw pixel values
+ */
+ fun onBuildCache(size: Size, density: Density)
+}
+
+/**
* Draw into a [Canvas] behind the modified content.
*/
fun Modifier.drawBehind(
@@ -43,6 +67,86 @@
}
/**
+ * Draw into a [DrawScope] with content that is persisted across
+ * draw calls as long as the size of the drawing area is the same or
+ * any state objects that are read have not changed. In the event that
+ * the drawing area changes, or the underlying state values that are being read
+ * change, this method is invoked again to recreate objects to be used during drawing
+ *
+ * For example, a [androidx.compose.ui.graphics.LinearGradient] that is to occupy the full
+ * bounds of the drawing area can be created once the size has been defined and referenced
+ * for subsequent draw calls without having to re-allocate.
+ *
+ * @sample androidx.compose.ui.samples.DrawWithCacheModifierSample
+ * @sample androidx.compose.ui.samples.DrawWithCacheModifierStateParameterSample
+ */
+fun Modifier.drawWithCache(
+ onBuildDrawCache: CacheDrawScope.() -> DrawResult
+) = composed {
+ val cacheDrawScope = remember { CacheDrawScope() }
+ this.then(DrawBackgroundCacheModifier(cacheDrawScope, onBuildDrawCache))
+}
+
+/**
+ * Handle to a drawing environment that enables caching of content based on the resolved size.
+ * Consumers define parameters and refer to them in the captured draw callback provided in
+ * [onDraw]
+ */
+class CacheDrawScope internal constructor(
+ internal var cachedDrawDensity: Density? = null
+) : Density {
+ internal var drawResult: DrawResult? = null
+
+ /**
+ * Provides the dimensions of the current drawing environment
+ */
+ var size: Size = Size.Unspecified
+ internal set
+
+ /**
+ * Specify the callback to be invoked to issue drawing commands
+ */
+ fun onDraw(block: DrawScope.() -> Unit): DrawResult {
+ return DrawResult(block).also { drawResult = it }
+ }
+
+ override val density: Float
+ get() = cachedDrawDensity!!.density
+
+ override val fontScale: Float
+ get() = cachedDrawDensity!!.density
+}
+
+private data class DrawBackgroundCacheModifier(
+ val cacheDrawScope: CacheDrawScope,
+ val onBuildDrawCache: CacheDrawScope.() -> DrawResult
+) : DrawCacheModifier {
+
+ override fun onBuildCache(size: Size, density: Density) {
+ cacheDrawScope.apply {
+ cachedDrawDensity = density
+ this.size = size
+ drawResult = null
+ onBuildDrawCache()
+ checkNotNull(drawResult) {
+ "DrawResult not defined, did you forget to call onDraw?"
+ }
+ }
+ }
+
+ override fun ContentDrawScope.draw() {
+ cacheDrawScope.drawResult?.block?.invoke(this)
+ drawContent()
+ }
+}
+
+/**
+ * Holder to a callback to be invoked during draw operations. This lambda
+ * captures and reuses parameters defined within the CacheDrawScope receiver scope lambda.
+ */
+class DrawResult internal constructor(internal var block: DrawScope.() -> Unit)
+
+/**
* Creates a [DrawModifier] that allows the developer to draw before or after the layout's
* contents. It also allows the modifier to adjust the layout's canvas.
*/
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/MeasureScope.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/MeasureScope.kt
index 60dcc6b..e133d99 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/MeasureScope.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/MeasureScope.kt
@@ -19,7 +19,6 @@
import androidx.compose.ui.MeasureScope.MeasureResult
import androidx.compose.ui.layout.IntrinsicMeasureScope
import androidx.compose.ui.unit.Constraints
-import androidx.compose.ui.unit.LayoutDirection
/**
* The receiver scope of a layout's measure lambda. The return value of the
@@ -67,30 +66,8 @@
override val height = height
override val alignmentLines = alignmentLines
override fun placeChildren() {
- with(InnerPlacementScope) {
- val previousParentWidth = parentWidth
- val previousLayoutDirection = parentLayoutDirection
- updateValuesForRtlMirroring(layoutDirection, width)
- placementBlock()
- updateValuesForRtlMirroring(previousLayoutDirection, previousParentWidth)
- }
- }
- }
-
- internal companion object {
- object InnerPlacementScope : Placeable.PlacementScope() {
- override var parentLayoutDirection = LayoutDirection.Ltr
- private set
- override var parentWidth = 0
- private set
-
- fun updateValuesForRtlMirroring(
- parentLayoutDirection: LayoutDirection,
- parentWidth: Int
- ) {
- this.parentLayoutDirection = parentLayoutDirection
- this.parentWidth = parentWidth
- }
+ Placeable.PlacementScope
+ .executeWithRtlMirroringValues(width, layoutDirection, placementBlock)
}
}
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/Placeable.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/Placeable.kt
index 4695179..cd35ccd 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/Placeable.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/Placeable.kt
@@ -111,14 +111,14 @@
* in RTL environment. If the value is zero, than the [Placeable] will be be placed to
* the original position (position will not be mirrored).
*/
- abstract val parentWidth: Int
+ protected abstract val parentWidth: Int
/**
* Keeps the layout direction of the parent of the placeable that is being places using
* current [PlacementScope]. Used to support automatic position mirroring for convenient
* RTL support in custom layouts.
*/
- abstract val parentLayoutDirection: LayoutDirection
+ protected abstract val parentLayoutDirection: LayoutDirection
/**
* Place a [Placeable] at [position] in its parent's coordinate system.
@@ -182,5 +182,26 @@
place(IntOffset(parentWidth - measuredSize.width - position.x, position.y))
}
}
+
+ internal companion object : PlacementScope() {
+ override var parentLayoutDirection = LayoutDirection.Ltr
+ private set
+ override var parentWidth = 0
+ private set
+
+ inline fun executeWithRtlMirroringValues(
+ parentWidth: Int,
+ parentLayoutDirection: LayoutDirection,
+ crossinline block: PlacementScope.() -> Unit
+ ) {
+ val previousParentWidth = this.parentWidth
+ val previousParentLayoutDirection = this.parentLayoutDirection
+ this.parentWidth = parentWidth
+ this.parentLayoutDirection = parentLayoutDirection
+ this.block()
+ this.parentWidth = previousParentWidth
+ this.parentLayoutDirection = previousParentLayoutDirection
+ }
+ }
}
}
\ No newline at end of file
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusManager.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusManager.kt
index aad72bf..61ef131 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusManager.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusManager.kt
@@ -20,17 +20,33 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusState.Active
import androidx.compose.ui.focus.FocusState.Inactive
+import androidx.compose.ui.gesture.PointerInputModifierImpl
+import androidx.compose.ui.gesture.TapGestureFilter
/**
* The focus manager is used by different [Owner][androidx.compose.ui.node.Owner] implementations
* to control focus.
+ *
+ * @param focusModifier The modifier that will be used as the root focus modifier.
*/
@ExperimentalFocus
-class FocusManager {
+internal class FocusManager(private val focusModifier: FocusModifier = FocusModifier(Inactive)) {
- private val focusModifier = FocusModifier(Inactive)
+ private val passThroughClickModifier = PointerInputModifierImpl(
+ TapGestureFilter().apply {
+ onTap = { clearFocus() }
+ consumeChanges = false
+ }
+ )
+
+ /**
+ * A [Modifier] that can be added to the [Owners][androidx.compose.ui.node.Owner] modifier
+ * list that contains the modifiers required by the foucus system. (Eg, a root focus modifier).
+ */
val modifier: Modifier
- get() = focusModifier
+ // TODO(b/168831247): return an empty Modifier when there are no focusable children.
+ get() = passThroughClickModifier
+ .then(focusModifier)
/**
* The [Owner][androidx.compose.ui.node.Owner] calls this function when it gains focus. This
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatingLayoutNodeWrapper.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatingLayoutNodeWrapper.kt
index ab66c6b..bf25e02 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatingLayoutNodeWrapper.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatingLayoutNodeWrapper.kt
@@ -27,7 +27,6 @@
import androidx.compose.ui.input.pointer.PointerInputFilter
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.util.nativeClass
/**
@@ -93,12 +92,11 @@
// our position in order ot know how to offset the value we provided).
if (wrappedBy?.isShallowPlacing == true) return
- with(InnerPlacementScope) {
- val previousParentWidth = this.parentWidth
- val previousLayoutDirection = this.parentLayoutDirection
- updateValuesForRtlMirroring(measureScope.layoutDirection, measuredSize.width)
+ PlacementScope.executeWithRtlMirroringValues(
+ measuredSize.width,
+ measureScope.layoutDirection
+ ) {
measureResult.placeChildren()
- updateValuesForRtlMirroring(previousLayoutDirection, previousParentWidth)
}
}
@@ -109,7 +107,7 @@
override val height: Int = wrapped.measureResult.height
override val alignmentLines: Map<AlignmentLine, Int> = emptyMap()
override fun placeChildren() {
- with(InnerPlacementScope) {
+ with(PlacementScope) {
placeable.place(-apparentToRealOffset)
}
}
@@ -165,15 +163,3 @@
_isAttached = false
}
}
-
-internal object InnerPlacementScope : Placeable.PlacementScope() {
- override var parentLayoutDirection = LayoutDirection.Ltr
- private set
- override var parentWidth = 0
- private set
-
- fun updateValuesForRtlMirroring(parentLayoutDirection: LayoutDirection, parentWidth: Int) {
- this.parentLayoutDirection = parentLayoutDirection
- this.parentWidth = parentWidth
- }
-}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
index 00ea94b..4888b4f 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
@@ -32,6 +32,7 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.OnPositionedModifier
import androidx.compose.ui.ParentDataModifier
+import androidx.compose.ui.Placeable
import androidx.compose.ui.Remeasurement
import androidx.compose.ui.RemeasurementModifier
import androidx.compose.ui.ZIndexModifier
@@ -40,7 +41,7 @@
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Canvas
import androidx.compose.ui.graphics.drawscope.DrawScope
-import androidx.compose.ui.graphics.drawscope.drawCanvas
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.input.key.KeyInputModifier
import androidx.compose.ui.input.pointer.PointerInputFilter
import androidx.compose.ui.input.pointer.PointerInputModifier
@@ -780,12 +781,11 @@
internal var needsOnPositionedDispatch = false
fun place(x: Int, y: Int) {
- with(InnerPlacementScope) {
- val previousParentWidth = parentWidth
- val previousLayoutDirection = parentLayoutDirection
- updateValuesForRtlMirroring(layoutDirection, outerMeasurablePlaceable.measuredWidth)
+ Placeable.PlacementScope.executeWithRtlMirroringValues(
+ outerMeasurablePlaceable.measuredWidth,
+ layoutDirection
+ ) {
outerMeasurablePlaceable.placeRelative(x, y)
- updateValuesForRtlMirroring(previousLayoutDirection, previousParentWidth)
}
}
@@ -1344,9 +1344,7 @@
private var wrapped: LayoutNodeWrapper? = null
override fun drawContent() {
- drawCanvas { canvas, _ ->
- wrapped?.draw(canvas)
- }
+ drawIntoCanvas { canvas -> wrapped?.draw(canvas) }
}
internal fun draw(
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt
index 0e4761e..b69647e 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt
@@ -61,7 +61,7 @@
open val invalidateLayerOnBoundsChange = true
private var _measureResult: MeasureScope.MeasureResult? = null
- var measureResult: MeasureScope.MeasureResult
+ open var measureResult: MeasureScope.MeasureResult
get() = _measureResult ?: error(UnmeasuredError)
internal set(value) {
if (invalidateLayerOnBoundsChange &&
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ModifiedDrawNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ModifiedDrawNode.kt
index 7f4cd55..fdce7d6 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ModifiedDrawNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ModifiedDrawNode.kt
@@ -16,9 +16,12 @@
package androidx.compose.ui.node
+import androidx.compose.ui.DrawCacheModifier
import androidx.compose.ui.DrawModifier
+import androidx.compose.ui.MeasureScope
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Canvas
+import androidx.compose.ui.unit.toSize
@OptIn(ExperimentalLayoutNodeApi::class)
internal class ModifiedDrawNode(
@@ -26,14 +29,47 @@
drawModifier: DrawModifier
) : DelegatingLayoutNodeWrapper<DrawModifier>(wrapped, drawModifier) {
+ private val cacheDrawModifier: DrawCacheModifier? =
+ if (drawModifier is DrawCacheModifier) {
+ drawModifier
+ } else {
+ null
+ }
+
+ // Flag to determine if the cache should be re-built
+ private var invalidateCache = true
+
+ // Callback used to build the drawing cache
+ private val updateCache = {
+ val size: Size = measuredSize.toSize()
+ cacheDrawModifier?.onBuildCache(size, layoutNode.mDrawScope)
+ invalidateCache = false
+ }
+
+ override var measureResult: MeasureScope.MeasureResult
+ get() = super.measureResult
+ set(value) {
+ if (super.measuredSize.width != value.width ||
+ super.measuredSize.height != value.height
+ ) {
+ invalidateCache = true
+ }
+ super.measureResult = value
+ }
+
// This is not thread safe
override fun draw(canvas: Canvas) {
+ val size = measuredSize.toSize()
+ if (cacheDrawModifier != null && invalidateCache) {
+ layoutNode.owner?.observeReads(
+ this,
+ onCommitAffectingModifiedDrawNode,
+ updateCache
+ )
+ }
+
val drawScope = layoutNode.mDrawScope
withPositionTranslation(canvas) {
- val size = Size(
- measuredSize.width.toFloat(),
- measuredSize.height.toFloat()
- )
drawScope.draw(canvas, size, wrapped) {
with(drawScope) {
with(modifier) {
@@ -43,4 +79,17 @@
}
}
}
+
+ companion object {
+ // Callback invoked whenever a state parameter that is read within the cache
+ // execution callback is updated. This marks the cache flag as dirty and
+ // invalidates the current layer.
+ private val onCommitAffectingModifiedDrawNode: (ModifiedDrawNode) -> Unit =
+ { modifiedDrawNode ->
+ // Note this intentionally does not invalidate the layer as Owner implementations
+ // already observe and invalidate the layer on state changes. Instead just
+ // mark the cache dirty so that it will be re-created on the next draw
+ modifiedDrawNode.invalidateCache = true
+ }
+ }
}
\ No newline at end of file
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OuterMeasurablePlaceable.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OuterMeasurablePlaceable.kt
index aea1a44..3b00627 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OuterMeasurablePlaceable.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OuterMeasurablePlaceable.kt
@@ -110,7 +110,7 @@
override fun placeAt(position: IntOffset) {
lastPosition = position
- with(InnerPlacementScope) {
+ with(PlacementScope) {
outerWrapper.place(position)
}
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
index 7795ee3..5a0691c 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
@@ -154,6 +154,12 @@
fun observeMeasureModelReads(node: LayoutNode, block: () -> Unit)
/**
+ * Observe model reads for any target, allowing consumers to determine how to respond
+ * to state changes
+ */
+ fun <T : Any> observeReads(target: T, onChanged: (T) -> Unit, block: () -> Unit)
+
+ /**
* Iterates through all LayoutNodes that have requested layout and measures and lays them out
*/
fun measureAndLayout()
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
index a44f0a9..69027ba 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
@@ -90,6 +90,14 @@
)
/**
+ * The horizontal scroll state of this node if this node is scrollable.
+ *
+ * @see SemanticsPropertyReceiver.horizontalAccessibilityScrollState
+ */
+ val HorizontalAccessibilityScrollState =
+ SemanticsPropertyKey<AccessibilityScrollState>("HorizontalAccessibilityScrollState")
+
+ /**
* Whether this semantics node represents a Popup. Not to be confused with if this node is
* _part of_ a Popup.
*
@@ -159,6 +167,14 @@
* @see SemanticsPropertyReceiver.textSelectionRange
*/
val TextSelectionRange = SemanticsPropertyKey<TextRange>("TextSelectionRange")
+
+ /**
+ * The vertical scroll state of this node if this node is scrollable.
+ *
+ * @see SemanticsPropertyReceiver.verticalAccessibilityScrollState
+ */
+ val VerticalAccessibilityScrollState =
+ SemanticsPropertyKey<AccessibilityScrollState>("VerticalAccessibilityScrollState")
}
/**
@@ -307,6 +323,21 @@
@IntRange(from = 0) val steps: Int = 0
)
+/**
+ * The scroll state of this node if this node is scrollable.
+ *
+ * @param value current scroll position value in pixels
+ * @param maxValue maximum bound for [value], or [Float.POSITIVE_INFINITY] if still unknown
+ * @param reverseScrolling for horizontal scroll, when this is `true`, 0 [value] will mean right,
+ * when`false`, 0 [value] will mean left. For vertical scroll, when this is `true`, 0 [value] will
+ * mean bottom, when `false`, 0 [value] will mean top
+ */
+data class AccessibilityScrollState(
+ val value: Float = 0f,
+ val maxValue: Float = 0f,
+ val reverseScrolling: Boolean = false
+)
+
interface SemanticsPropertyReceiver {
operator fun <T> set(key: SemanticsPropertyKey<T>, value: T)
}
@@ -363,6 +394,22 @@
}
/**
+ * The horizontal scroll state of this node if this node is scrollable.
+ *
+ * @see SemanticsProperties.HorizontalAccessibilityScrollState
+ */
+var SemanticsPropertyReceiver.horizontalAccessibilityScrollState
+ by SemanticsProperties.HorizontalAccessibilityScrollState
+
+/**
+ * The vertical scroll state of this node if this node is scrollable.
+ *
+ * @see SemanticsProperties.VerticalAccessibilityScrollState
+ */
+var SemanticsPropertyReceiver.verticalAccessibilityScrollState
+ by SemanticsProperties.VerticalAccessibilityScrollState
+
+/**
* Whether this semantics node represents a Popup. Not to be confused with if this node is
* _part of_ a Popup.
*
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.kt
index 2a86c3b..2f04988 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.kt
@@ -40,6 +40,7 @@
import androidx.compose.ui.input.pointer.PointerInputEventProcessor
import androidx.compose.ui.input.pointer.PointerInputFilter
import androidx.compose.ui.input.pointer.PointerMoveEventFilter
+import androidx.compose.ui.layout.globalBounds
import androidx.compose.ui.node.ExperimentalLayoutNodeApi
import androidx.compose.ui.node.InternalCoreApi
import androidx.compose.ui.node.LayoutNode
@@ -180,6 +181,10 @@
snapshotObserver.observeReads(node, onCommitAffectingMeasure, block)
}
+ override fun <T : Any> observeReads(target: T, onChanged: (T) -> Unit, block: () -> Unit) {
+ snapshotObserver.observeReads(target, onChanged, block)
+ }
+
private fun observeDrawModelReads(layer: SkijaLayer, block: () -> Unit) {
snapshotObserver.observeReads(layer, onCommitAffectingLayer, block)
}
@@ -261,8 +266,10 @@
.asSequence()
.filterIsInstance<PointerMoveEventFilter>()
) {
- if (!onMoveConsumed)
- onMoveConsumed = filter.onMoveHandler(position)
+ if (!onMoveConsumed) {
+ val relative = position - filter.layoutCoordinates.globalBounds.topLeft
+ onMoveConsumed = filter.onMoveHandler(relative)
+ }
if (!onEnterConsumed && !oldMoveFilters.contains(filter))
onEnterConsumed = filter.onEnterHandler()
}
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/focus/FocusManagerTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/focus/FocusManagerTest.kt
index c29bc230..05caee2 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/focus/FocusManagerTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/focus/FocusManagerTest.kt
@@ -40,15 +40,15 @@
ExperimentalLayoutNodeApi::class
)
@RunWith(Parameterized::class)
-class FocusManagerTest(val initialFocusState: FocusState) {
+class FocusManagerTest(private val initialFocusState: FocusState) {
companion object {
@JvmStatic
@Parameterized.Parameters(name = "rootInitialFocus = {0}")
fun initParameters() = FocusState.values()
}
- private val focusManager = FocusManager()
- private val focusModifier: FocusModifier = focusManager.modifier as FocusModifier
+ private val focusModifier = FocusModifier(Inactive)
+ private val focusManager = FocusManager(focusModifier)
@Before
fun setup() {
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
index cb823e0..46385b9 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
@@ -1720,6 +1720,10 @@
block()
}
+ override fun <T : Any> observeReads(target: T, onChanged: (T) -> Unit, block: () -> Unit) {
+ block()
+ }
+
override fun measureAndLayout() {
}
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ContentAccessProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ContentAccessProcessor.kt
index cde30d1..4cf63d3 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ContentAccessProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ContentAccessProcessor.kt
@@ -46,13 +46,13 @@
class ContentAccessProcessStep(val processingEnv: ProcessingEnvironment) : ProcessingStep {
@KotlinPoetMetadataPreview
override fun process(elementsByAnnotation: SetMultimap<Class<out Annotation>, Element>?):
- Set<Element> {
+ Set<Element> {
- elementsByAnnotation?.get(ContentAccessObject::class.java)?.forEach {
- ContentAccessObjectProcessor(MoreElements.asType(it), processingEnv).process()
+ elementsByAnnotation?.get(ContentAccessObject::class.java)?.forEach {
+ ContentAccessObjectProcessor(MoreElements.asType(it), processingEnv).process()
+ }
+ return emptySet()
}
- return emptySet()
- }
override fun annotations(): MutableSet<out Class<out Annotation>> {
return mutableSetOf(ContentAccessObject::class.java)
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/element_ext.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/element_ext.kt
index 69f100a..a5e990b 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/element_ext.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/element_ext.kt
@@ -64,36 +64,36 @@
fun TypeElement.isFilledThroughConstructor() = this.getNonPrivateNonIgnoreConstructors().size == 1
fun TypeElement.isNotInstantiable():
- Boolean {
- // No constructors means we can't instantiate it to fill its public fields, user might have
- // made the default constructor private or simply ignored it.
- return this.getNonPrivateNonIgnoreConstructors().isEmpty()
-}
+ Boolean {
+ // No constructors means we can't instantiate it to fill its public fields, user might have
+ // made the default constructor private or simply ignored it.
+ return this.getNonPrivateNonIgnoreConstructors().isEmpty()
+ }
/**
* Gets either all the parameters of the single public constructor if they exist, otherwise returns
* a list of all public fields, even if empty.
*/
fun TypeElement.getAllConstructorParamsOrPublicFields():
- List<VariableElement> {
- val constructors = this.getNonPrivateNonIgnoreConstructors()
+ List<VariableElement> {
+ val constructors = this.getNonPrivateNonIgnoreConstructors()
- if (constructors.size == 1) {
- val parameters = MoreElements.asExecutable(constructors.first()).parameters
- if (parameters.isNotEmpty()) {
- return parameters.map { it as VariableElement }
+ if (constructors.size == 1) {
+ val parameters = MoreElements.asExecutable(constructors.first()).parameters
+ if (parameters.isNotEmpty()) {
+ return parameters.map { it as VariableElement }
+ }
+ } else if (constructors.isEmpty()) {
+ error("${this.qualifiedName} has no non private and non ignored constructors!")
+ } else {
+ error("${this.qualifiedName} has more than non private non ignored constructor")
}
- } else if (constructors.isEmpty()) {
- error("${this.qualifiedName} has no non private and non ignored constructors!")
- } else {
- error("${this.qualifiedName} has more than non private non ignored constructor")
+ // TODO(obenabde): explore ways to warn users if they're unknowingly doing something wrong
+ // e.g if there is a possibility they think we are filling fields instead of constructors
+ // or both etc...
+ // This is a class with an empty or no public constructor, check public fields.
+ return getAllNonPrivateFieldsIncludingSuperclassOnes()
}
- // TODO(obenabde): explore ways to warn users if they're unknowingly doing something wrong
- // e.g if there is a possibility they think we are filling fields instead of constructors
- // or both etc...
- // This is a class with an empty or no public constructor, check public fields.
- return getAllNonPrivateFieldsIncludingSuperclassOnes()
-}
fun TypeElement.getAllNonPrivateFieldsIncludingSuperclassOnes(): List<VariableElement> {
var nonPrivateFields = ElementFilter.fieldsIn(this.enclosedElements)
@@ -117,11 +117,14 @@
}
fun TypeMirror.extendsBound(): TypeMirror? {
- return this.accept(object : SimpleTypeVisitor7<TypeMirror?, Void?>() {
- override fun visitWildcard(type: WildcardType, ignored: Void?): TypeMirror? {
- return type.extendsBound ?: type.superBound
- }
- }, null)
+ return this.accept(
+ object : SimpleTypeVisitor7<TypeMirror?, Void?>() {
+ override fun visitWildcard(type: WildcardType, ignored: Void?): TypeMirror? {
+ return type.extendsBound ?: type.superBound
+ }
+ },
+ null
+ )
}
@KotlinPoetMetadataPreview
@@ -130,25 +133,28 @@
@KotlinPoetMetadataPreview
fun ExecutableElement.getSuspendFunctionReturnType():
- TypeMirror {
- val typeParam = MoreTypes.asDeclared(parameters.last().asType()).typeArguments.first()
- return typeParam.extendsBound() ?: typeParam
-}
+ TypeMirror {
+ val typeParam = MoreTypes.asDeclared(parameters.last().asType()).typeArguments.first()
+ return typeParam.extendsBound() ?: typeParam
+ }
@KotlinPoetMetadataPreview
fun ExecutableElement.getKotlinFunspec(processingEnv: ProcessingEnvironment):
- FunSpec {
- val classInspector = ElementsClassInspector.create(processingEnv.elementUtils, processingEnv
- .typeUtils)
- val enclosingClass = this.enclosingElement as TypeElement
+ FunSpec {
+ val classInspector = ElementsClassInspector.create(
+ processingEnv.elementUtils,
+ processingEnv
+ .typeUtils
+ )
+ val enclosingClass = this.enclosingElement as TypeElement
- val kotlinApi = enclosingClass.toTypeSpec(classInspector)
- val jvmSignature = JvmSignatureUtil.getMethodDescriptor(this)
- val funSpec = kotlinApi.funSpecs.find {
- it.tag<ImmutableKmFunction>()?.signature?.asString() == jvmSignature
- } ?: error("No matching funSpec found for $jvmSignature.")
- return funSpec
-}
+ val kotlinApi = enclosingClass.toTypeSpec(classInspector)
+ val jvmSignature = JvmSignatureUtil.getMethodDescriptor(this)
+ val funSpec = kotlinApi.funSpecs.find {
+ it.tag<ImmutableKmFunction>()?.signature?.asString() == jvmSignature
+ } ?: error("No matching funSpec found for $jvmSignature.")
+ return funSpec
+ }
fun TypeElement.getAllMethodsIncludingSupers(): Set<ExecutableElement> {
val myMethods = ElementFilter.methodsIn(this.enclosedElements).toSet()
@@ -217,20 +223,24 @@
}
method.name to result
}
- return AnnotationBox(Proxy.newProxyInstance(ClassGetter::class.java.classLoader,
- arrayOf(cl, ClassGetter::class.java)) { _, method, args ->
- when (method.name) {
- ClassGetter::getAsTypeMirror.name -> map[args[0]]
- ClassGetter::getAsTypeMirrorList.name -> map[args[0]]
- "getAsAnnotationBox" -> map[args[0]]
- "getAsAnnotationBoxArray" -> map[args[0]]
- else -> map[method.name]
+ return AnnotationBox(
+ Proxy.newProxyInstance(
+ ClassGetter::class.java.classLoader,
+ arrayOf(cl, ClassGetter::class.java)
+ ) { _, method, args ->
+ when (method.name) {
+ ClassGetter::getAsTypeMirror.name -> map[args[0]]
+ ClassGetter::getAsTypeMirrorList.name -> map[args[0]]
+ "getAsAnnotationBox" -> map[args[0]]
+ "getAsAnnotationBoxArray" -> map[args[0]]
+ else -> map[method.name]
+ }
}
- })
+ )
}
fun <T : Annotation> Element.toAnnotationBox(cl: KClass<T>) =
- MoreElements.getAnnotationMirror(this, cl.java).orNull()?.box(cl.java)
+ MoreElements.getAnnotationMirror(this, cl.java).orNull()?.box(cl.java)
@Suppress("DEPRECATION")
private class ListVisitor<T : Annotation>(private val annotationClass: Class<T>) :
@@ -355,7 +365,7 @@
return object : SimpleAnnotationValueVisitor6<T, Void>() {
override fun visitEnumConstant(value: VariableElement?, p: Void?): T {
return enumClass.getDeclaredMethod("valueOf", String::class.java)
- .invoke(null, value!!.simpleName.toString()) as T
+ .invoke(null, value!!.simpleName.toString()) as T
}
}.visit(this)
}
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/type_mirror_ext.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/type_mirror_ext.kt
index 53ea666..ffb4433 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/type_mirror_ext.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/type_mirror_ext.kt
@@ -52,18 +52,21 @@
}
fun TypeMirror.extractImmediateTypeParameter():
- TypeMirror {
- val asDeclared = MoreTypes.asDeclared(this)
- return asDeclared.typeArguments.first()
-}
+ TypeMirror {
+ val asDeclared = MoreTypes.asDeclared(this)
+ return asDeclared.typeArguments.first()
+ }
fun TypeMirror.extractIntendedReturnType(): TypeMirror {
if (!this.isSupportedGenericType()) {
return this
}
val firstWrappedType = extractImmediateTypeParameter()
- if (isFlowable() && (firstWrappedType.isSupportedCollection() ||
- firstWrappedType.isOptional())) {
+ if (isFlowable() && (
+ firstWrappedType.isSupportedCollection() ||
+ firstWrappedType.isOptional()
+ )
+ ) {
return firstWrappedType.extractImmediateTypeParameter()
}
return firstWrappedType
@@ -138,22 +141,31 @@
fun TypeMirror.isDouble() = isPrimitiveDouble() || isBoxedDouble()
-fun TypeMirror.isString() = MoreTypes.isType(this) && MoreTypes.isTypeOf(String::class
- .java, this)
+fun TypeMirror.isString() = MoreTypes.isType(this) && MoreTypes.isTypeOf(
+ String::class
+ .java,
+ this
+)
-fun TypeMirror.isPrimitiveBlob() = MoreTypes.isType(this) && MoreTypes.isTypeOf(ByteArray::class
- .java, this)
+fun TypeMirror.isPrimitiveBlob() = MoreTypes.isType(this) && MoreTypes.isTypeOf(
+ ByteArray::class
+ .java,
+ this
+)
-fun TypeMirror.isBoxedBlob() = MoreTypes.isType(this) && MoreTypes.isTypeOf(Array<Byte>::class
- .java, this)
+fun TypeMirror.isBoxedBlob() = MoreTypes.isType(this) && MoreTypes.isTypeOf(
+ Array<Byte>::class
+ .java,
+ this
+)
fun TypeMirror.isBlob() = isPrimitiveBlob() || isBoxedBlob()
fun TypeMirror.isSupportedColumnType() = isBlob() || isInt() || isString() || isFloat() ||
- isDouble() || isShort() || isLong()
+ isDouble() || isShort() || isLong()
fun TypeMirror.isPrimitive(): Boolean = isPrimitiveLong() || isPrimitiveShort() ||
- isPrimitiveBlob() || isPrimitiveDouble() || isPrimitiveFloat() || isPrimitiveInt()
+ isPrimitiveBlob() || isPrimitiveDouble() || isPrimitiveFloat() || isPrimitiveInt()
fun TypeMirror.getCursorMethod(): String {
if (isShort()) {
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentAccessObjectProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentAccessObjectProcessor.kt
index af1eb98..9002873 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentAccessObjectProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentAccessObjectProcessor.kt
@@ -36,19 +36,25 @@
class ContentAccessObjectProcessor(
val element: TypeElement,
private val processingEnv:
- ProcessingEnvironment
+ ProcessingEnvironment
) {
@KotlinPoetMetadataPreview
fun process() {
val errorReporter = ErrorReporter(processingEnv.messager)
if (element.kind != ElementKind.INTERFACE) {
- errorReporter.reportError("Only interfaces should be annotated with " +
- "@ContentAccessObject, '${element.qualifiedName}' is not interface.", element)
+ errorReporter.reportError(
+ "Only interfaces should be annotated with " +
+ "@ContentAccessObject, '${element.qualifiedName}' is not interface.",
+ element
+ )
} else {
if (element.getAllMethodsIncludingSupers().isEmpty()) {
- errorReporter.reportError("Interface '${element.qualifiedName}' annotated with " +
+ errorReporter.reportError(
+ "Interface '${element.qualifiedName}' annotated with " +
"@ContentAccessObject doesn't delcare any functions. Interfaces annotated" +
- " with @ContentAccessObject should declare at least one function.", element)
+ " with @ContentAccessObject should declare at least one function.",
+ element
+ )
}
}
val contentEntityType = element.toAnnotationBox(ContentAccessObject::class)!!
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessor.kt
index cfb0324..d317ce7 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessor.kt
@@ -45,8 +45,10 @@
fun processEntity(): ContentEntityVO? {
val entity = contentEntity.asTypeElement()
if (entity.hasMoreThanOneNonPrivateNonIgnoredConstructor()) {
- errorReporter.reportError(entityWithMultipleConstructors(contentEntity.toString()),
- entity)
+ errorReporter.reportError(
+ entityWithMultipleConstructors(contentEntity.toString()),
+ entity
+ )
return null
} else if (entity.isNotInstantiable()) {
errorReporter.reportError(nonInstantiableEntity(contentEntity.toString()), entity)
@@ -54,19 +56,34 @@
}
val columns = entity.getAllConstructorParamsOrPublicFields()
columns.forEach {
- if (fieldIsNullable(it) && (it.asType().isPrimitive() &&
- !it.asType().isPrimitiveBlob())) {
- errorReporter.reportError(entityWithNullablePrimitiveType(it.simpleName.toString(),
- contentEntity.toString()), it)
+ if (fieldIsNullable(it) && (
+ it.asType().isPrimitive() &&
+ !it.asType().isPrimitiveBlob()
+ )
+ ) {
+ errorReporter.reportError(
+ entityWithNullablePrimitiveType(
+ it.simpleName.toString(),
+ contentEntity.toString()
+ ),
+ it
+ )
}
}
val contentColumns = HashMap<String, ContentColumnVO>()
val contentPrimaryKey = ArrayList<ContentColumnVO>()
columns.forEach { column ->
if (column.hasAnnotation(ContentColumn::class) &&
- column.hasAnnotation(ContentPrimaryKey::class)) {
- errorReporter.reportError(entityFieldWithBothAnnotations(column.simpleName
- .toString(), entity.qualifiedName.toString()), entity)
+ column.hasAnnotation(ContentPrimaryKey::class)
+ ) {
+ errorReporter.reportError(
+ entityFieldWithBothAnnotations(
+ column.simpleName
+ .toString(),
+ entity.qualifiedName.toString()
+ ),
+ entity
+ )
} else if (column.hasAnnotation(ContentColumn::class)) {
if (validateColumnType(column, errorReporter)) {
val vo = ContentColumnVO(
@@ -79,8 +96,10 @@
}
} else if (column.hasAnnotation(ContentPrimaryKey::class)) {
if (validateColumnType(column, errorReporter)) {
- val vo = ContentColumnVO(column.simpleName.toString(), column.asType(), column
- .getAnnotation(ContentPrimaryKey::class.java).columnName,
+ val vo = ContentColumnVO(
+ column.simpleName.toString(), column.asType(),
+ column
+ .getAnnotation(ContentPrimaryKey::class.java).columnName,
fieldIsNullable(column),
fieldRequiresApi(column)
)
@@ -99,11 +118,21 @@
}
if (contentPrimaryKey.isEmpty()) {
if (columns.isEmpty()) {
- errorReporter.reportError(missingFieldsInContentEntityErrorMessage(entity
- .qualifiedName.toString()), entity)
+ errorReporter.reportError(
+ missingFieldsInContentEntityErrorMessage(
+ entity
+ .qualifiedName.toString()
+ ),
+ entity
+ )
} else {
- errorReporter.reportError(missingEntityPrimaryKeyErrorMessage(entity
- .qualifiedName.toString()), entity)
+ errorReporter.reportError(
+ missingEntityPrimaryKeyErrorMessage(
+ entity
+ .qualifiedName.toString()
+ ),
+ entity
+ )
}
}
if (contentPrimaryKey.size > 1) {
@@ -115,17 +144,24 @@
if (errorReporter.errorReported) {
return null
}
- return ContentEntityVO(entity.getAnnotation(ContentEntity::class.java).uri, MoreTypes
- .asDeclared(entity.asType()), contentColumns, contentPrimaryKey.first())
+ return ContentEntityVO(
+ entity.getAnnotation(ContentEntity::class.java).uri,
+ MoreTypes
+ .asDeclared(entity.asType()),
+ contentColumns, contentPrimaryKey.first()
+ )
}
fun validateColumnType(column: VariableElement, errorReporter: ErrorReporter): Boolean {
if (!column.asType().isSupportedColumnType()) {
errorReporter.reportError(
- unsupportedColumnType(column.simpleName.toString(),
+ unsupportedColumnType(
+ column.simpleName.toString(),
contentEntity.toString(),
column.asType().toString()
- ), column)
+ ),
+ column
+ )
return false
}
return true
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessor.kt
index 0fc343b..955e06b 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessor.kt
@@ -56,7 +56,8 @@
return null
} else if (entitiesInParams.isEmpty()) {
errorReporter.reportError(
- insertMethodHasNoEntityInParameters(), method)
+ insertMethodHasNoEntityInParameters(), method
+ )
return null
}
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessor.kt
index 105b4d8..9c69ff6 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessor.kt
@@ -61,8 +61,10 @@
val potentialContentEntity = method.toAnnotationBox(ContentQuery::class)!!
.getAsTypeMirror("contentEntity")!!
val resolvedContentEntity = if (!potentialContentEntity.isVoidObject()) {
- ContentEntityProcessor(potentialContentEntity,
- processingEnv, errorReporter).processEntity()
+ ContentEntityProcessor(
+ potentialContentEntity,
+ processingEnv, errorReporter
+ ).processEntity()
} else {
contentEntity
}
@@ -70,8 +72,10 @@
errorReporter.reportError(missingEntityOnMethod(method.simpleName.toString()), method)
return null
}
- val toBeUsedUri = determineToBeUsedUri(resolvedContentEntity, contentQueryAnnotation.uri,
- errorReporter, method)
+ val toBeUsedUri = determineToBeUsedUri(
+ resolvedContentEntity, contentQueryAnnotation.uri,
+ errorReporter, method
+ )
if (toBeUsedUri.isEmpty()) {
errorReporter.reportError(missingUriOnMethod(), method)
}
@@ -82,8 +86,11 @@
// Maybe it was "column desc" or "column asc", check.
val splitOrderBy = trimmedOrderByMember.split(" ")
if (splitOrderBy.size == 2 && resolvedContentEntity.columns.containsKey
- (splitOrderBy.get(0)) && ORDER_BY_KEYWORDS.contains(splitOrderBy
- .get(1))) {
+ (splitOrderBy.get(0)) && ORDER_BY_KEYWORDS.contains(
+ splitOrderBy
+ .get(1)
+ )
+ ) {
continue
}
errorReporter.reportError(badlyFormulatedOrderBy(orderByMember), method)
@@ -100,27 +107,44 @@
val selectionVO = if (contentQueryAnnotation.selection.isEmpty()) {
null
} else {
- SelectionProcessor(method, contentQueryAnnotation.selection,
- paramsNamesAndTypes, errorReporter, resolvedContentEntity).process()
+ SelectionProcessor(
+ method, contentQueryAnnotation.selection,
+ paramsNamesAndTypes, errorReporter, resolvedContentEntity
+ ).process()
}
if (contentQueryAnnotation.projection.size == 1 &&
- returnType.extractIntendedReturnType().isSupportedColumnType()) {
+ returnType.extractIntendedReturnType().isSupportedColumnType()
+ ) {
val queriedColumn = contentQueryAnnotation.projection[0]
if (!resolvedContentEntity.columns.containsKey(queriedColumn)) {
- errorReporter.reportError(queriedColumnInProjectionNotInEntity(queriedColumn,
- resolvedContentEntity.type.toString()), method)
+ errorReporter.reportError(
+ queriedColumnInProjectionNotInEntity(
+ queriedColumn,
+ resolvedContentEntity.type.toString()
+ ),
+ method
+ )
return null
}
val queriedColumnType = resolvedContentEntity.columns.get(queriedColumn)!!.type
if (queriedColumnType.boxIfPrimitive(processingEnv).toString()
!= returnType.boxIfPrimitive(processingEnv).toString() &&
- ((!returnType.isSupportedGenericType() ||
- !processingEnv.typeUtils
- .isSameType(returnType.extractIntendedReturnType(),
- queriedColumnType.boxIfPrimitive(processingEnv))))) {
+ (
+ (
+ !returnType.isSupportedGenericType() ||
+ !processingEnv.typeUtils
+ .isSameType(
+ returnType.extractIntendedReturnType(),
+ queriedColumnType.boxIfPrimitive(processingEnv)
+ )
+ )
+ )
+ ) {
errorReporter.reportError(
- queriedColumnInProjectionTypeDoesntMatchReturnType(returnType.toString(),
- queriedColumnType.toString(), queriedColumn),
+ queriedColumnInProjectionTypeDoesntMatchReturnType(
+ returnType.toString(),
+ queriedColumnType.toString(), queriedColumn
+ ),
method
)
}
@@ -135,7 +159,8 @@
returnType = returnType,
method = method,
orderBy = orderBy,
- isSuspend = isSuspendFunction)
+ isSuspend = isSuspendFunction
+ )
} else {
// Either empty projection or more than one field, either way infer the return columns
// from the return type POJO/entity.
@@ -149,7 +174,8 @@
uri = toBeUsedUri,
returnType = returnType,
method = method,
- isSuspend = isSuspendFunction)
+ isSuspend = isSuspendFunction
+ )
}
val intendedReturnType = if (returnType.isSupportedGenericType()) {
@@ -159,27 +185,42 @@
}
if (intendedReturnType.asTypeElement()
- .hasMoreThanOneNonPrivateNonIgnoredConstructor()) {
+ .hasMoreThanOneNonPrivateNonIgnoredConstructor()
+ ) {
errorReporter.reportError(
pojoHasMoreThanOneQualifyingConstructor(intendedReturnType.toString()),
- intendedReturnType.asTypeElement())
+ intendedReturnType.asTypeElement()
+ )
return null
} else if (intendedReturnType.asTypeElement().isNotInstantiable()) {
- errorReporter.reportError(pojoIsNotInstantiable(intendedReturnType.asTypeElement()
- .qualifiedName.toString()), intendedReturnType.asTypeElement())
+ errorReporter.reportError(
+ pojoIsNotInstantiable(
+ intendedReturnType.asTypeElement()
+ .qualifiedName.toString()
+ ),
+ intendedReturnType.asTypeElement()
+ )
return null
}
val pojo = PojoProcessor(intendedReturnType).process()
// Apply the projection (if existing) to the POJO
- val pojoWithProjection = validateAndApplyProjectionToPojo(contentQueryAnnotation
- .projection, pojo, returnType, resolvedContentEntity)
+ val pojoWithProjection = validateAndApplyProjectionToPojo(
+ contentQueryAnnotation
+ .projection,
+ pojo, returnType, resolvedContentEntity
+ )
if (errorReporter.errorReported) {
return null
}
pojoWithProjection!!.pojoFields.forEach {
if (it.isNullable && it.type.isPrimitive()) {
- errorReporter.reportError(pojoWithNullablePrimitive(it.name,
- pojo.type.toString()), method)
+ errorReporter.reportError(
+ pojoWithNullablePrimitive(
+ it.name,
+ pojo.type.toString()
+ ),
+ method
+ )
}
}
return ContentQueryVO(
@@ -204,24 +245,35 @@
) {
pojo.pojoFields.forEach { field ->
if (!resolvedContentEntity.columns.containsKey(field.columnName) || !processingEnv
- .typeUtils.isSameType(resolvedContentEntity.columns.get(field.columnName)!!
- .type.boxIfPrimitive(processingEnv),
- field.type.boxIfPrimitive(processingEnv)
- )) {
- errorReporter.reportError(pojoFieldNotInEntity(field.name, field.type.toString(),
- field.columnName, pojo.type.toString(), resolvedContentEntity.type.toString()),
- method)
+ .typeUtils.isSameType(
+ resolvedContentEntity.columns.get(field.columnName)!!
+ .type.boxIfPrimitive(processingEnv),
+ field.type.boxIfPrimitive(processingEnv)
+ )
+ ) {
+ errorReporter.reportError(
+ pojoFieldNotInEntity(
+ field.name, field.type.toString(),
+ field.columnName, pojo.type.toString(),
+ resolvedContentEntity.type.toString()
+ ),
+ method
+ )
} else {
if (resolvedContentEntity.columns.get(field.columnName)!!.isNullable &&
- !field.isNullable) {
+ !field.isNullable
+ ) {
// TODO(obenabde): clarify how to mark as nullable, i.e "?" for Kotlin and
// @androidx.annotations.Nullable for Java.
- errorReporter.reportError(nullableEntityColumnNotNullableInPojo(
- field.name,
- field.type.toString(),
- field.columnName,
- resolvedContentEntity.type.toString()
- ), method)
+ errorReporter.reportError(
+ nullableEntityColumnNotNullableInPojo(
+ field.name,
+ field.type.toString(),
+ field.columnName,
+ resolvedContentEntity.type.toString()
+ ),
+ method
+ )
}
}
}
@@ -243,17 +295,28 @@
for (column in projection) {
if (!extractedColumnNames.containsKey(column)) {
errorFound = true
- errorReporter.reportError(columnInProjectionNotIncludedInReturnPojo(column,
- pojo.type.toString()), method)
+ errorReporter.reportError(
+ columnInProjectionNotIncludedInReturnPojo(
+ column,
+ pojo.type.toString()
+ ),
+ method
+ )
}
}
for (pojoField in pojo.pojoFields) {
if (!projection.contains(pojoField.columnName) && !pojoField.isNullable &&
- pojo.type.asTypeElement().isFilledThroughConstructor()) {
+ pojo.type.asTypeElement().isFilledThroughConstructor()
+ ) {
errorFound = true
errorReporter.reportError(
- constructorFieldNotIncludedInProjectionNotNullable(pojoField.name, returnType
- .extractIntendedReturnType().toString()), method)
+ constructorFieldNotIncludedInProjectionNotNullable(
+ pojoField.name,
+ returnType
+ .extractIntendedReturnType().toString()
+ ),
+ method
+ )
}
}
if (errorFound) {
@@ -287,15 +350,18 @@
errorReporter.reportError(columnOnlyAsUri(), method)
return uriInAnnotation
} else if (!method.parameters.map { it.simpleName.toString() }.contains
- (specifiedParamName)) {
+ (specifiedParamName)
+ ) {
errorReporter.reportError(missingUriParameter(specifiedParamName), method)
return uriInAnnotation
} else if (!method.parameters.filter {
- it.simpleName.toString().equals(specifiedParamName) }[0].asType().isString()) {
+ it.simpleName.toString().equals(specifiedParamName)
+ }[0].asType().isString()
+ ) {
errorReporter.reportError(uriParameterIsNotString(specifiedParamName), method)
return uriInAnnotation
}
return uriInAnnotation
}
-internal val ORDER_BY_KEYWORDS = listOf("asc", "desc")
\ No newline at end of file
+internal val ORDER_BY_KEYWORDS = listOf("asc", "desc")
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessor.kt
index 7172823..1a46f41 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessor.kt
@@ -53,8 +53,10 @@
val potentialContentEntity = method.toAnnotationBox(ContentUpdate::class)!!
.getAsTypeMirror("contentEntity")!!
val resolvedContentEntity = if (!potentialContentEntity.isVoidObject()) {
- ContentEntityProcessor(potentialContentEntity,
- processingEnv, errorReporter).processEntity()
+ ContentEntityProcessor(
+ potentialContentEntity,
+ processingEnv, errorReporter
+ ).processEntity()
} else {
contentEntity
}
@@ -62,8 +64,10 @@
errorReporter.reportError(missingEntityOnMethod(method.simpleName.toString()), method)
return null
}
- val toBeUsedUri = determineToBeUsedUri(resolvedContentEntity, contentUpdateAnnotation.uri,
- errorReporter, method)
+ val toBeUsedUri = determineToBeUsedUri(
+ resolvedContentEntity, contentUpdateAnnotation.uri,
+ errorReporter, method
+ )
if (toBeUsedUri.isEmpty()) {
errorReporter.reportError(missingUriOnMethod(), method)
}
@@ -82,22 +86,27 @@
// happen atomically. Anyhow it would be easier to do the other way through
// parameters annotated with @ContentColumn. Explore this further later on, although I
// doubt we need to worry about this so much for the updates
- errorReporter.reportError(updatingMultipleEntitiesAtTheSameType
+ errorReporter.reportError(
+ updatingMultipleEntitiesAtTheSameType
(resolvedContentEntity.type.toString(), method.simpleName.toString()),
- method)
+ method
+ )
return null
}
if (entitiesInParams.size == 1) {
// Assume the user wants to update a single entity
if (contentUpdateAnnotation.where.isNotEmpty()) {
- errorReporter.reportError(methodSpecifiesWhereClauseWhenUpdatingUsingEntity
- (entitiesInParams.first().toString()), method)
+ errorReporter.reportError(
+ methodSpecifiesWhereClauseWhenUpdatingUsingEntity
+ (entitiesInParams.first().toString()),
+ method
+ )
return null
}
val primaryKeyColumnName = resolvedContentEntity.primaryKeyColumn.columnName
val primaryKeyVariableName = resolvedContentEntity.primaryKeyColumn.name
val whereClause = "$primaryKeyColumnName = \${${entitiesInParams.first()}" +
- ".$primaryKeyVariableName}"
+ ".$primaryKeyVariableName}"
val updateList = mutableListOf<Pair<String, String>>()
for (entityColumn in resolvedContentEntity.columns.values) {
if (entityColumn.columnName != primaryKeyColumnName) {
@@ -124,8 +133,10 @@
val selectionVO = if (contentUpdateAnnotation.where.isEmpty()) {
null
} else {
- SelectionProcessor(method, contentUpdateAnnotation.where,
- paramsNamesAndTypes, errorReporter, resolvedContentEntity).process()
+ SelectionProcessor(
+ method, contentUpdateAnnotation.where,
+ paramsNamesAndTypes, errorReporter, resolvedContentEntity
+ ).process()
}
val contentValues = mutableListOf<Pair<String, String>>()
var foundContentColumnAnnotatedParameters = false
@@ -134,22 +145,37 @@
foundContentColumnAnnotatedParameters = true
val columnName = param.getAnnotation(ContentColumn::class.java).columnName
if (!resolvedContentEntity.columns.containsKey(columnName)) {
- errorReporter.reportError(columnInContentUpdateParametersNotInEntity(
- param.simpleName.toString(), columnName,
- resolvedContentEntity.type.toString()), method)
- } else if (param.asType().boxIfPrimitive(processingEnv) != resolvedContentEntity
- .columns.get(columnName)!!.type.boxIfPrimitive(processingEnv)) {
errorReporter.reportError(
- mismatchedColumnTypeForColumnToBeUpdated(param.simpleName.toString(),
- columnName, param.asType().toString(), resolvedContentEntity.type
- .toString(), resolvedContentEntity.columns.get(columnName)!!.type
- .toString()),
- method)
+ columnInContentUpdateParametersNotInEntity(
+ param.simpleName.toString(), columnName,
+ resolvedContentEntity.type.toString()
+ ),
+ method
+ )
+ } else if (param.asType().boxIfPrimitive(processingEnv) != resolvedContentEntity
+ .columns.get(columnName)!!.type.boxIfPrimitive(processingEnv)
+ ) {
+ errorReporter.reportError(
+ mismatchedColumnTypeForColumnToBeUpdated(
+ param.simpleName.toString(),
+ columnName, param.asType().toString(),
+ resolvedContentEntity.type
+ .toString(),
+ resolvedContentEntity.columns.get(columnName)!!.type
+ .toString()
+ ),
+ method
+ )
} else if (fieldIsNullable(param) && !resolvedContentEntity
- .columns.get(columnName)!!.isNullable) {
- errorReporter.reportError(nullableUpdateParamForNonNullableEntityColumn(
- param.simpleName.toString(), columnName,
- resolvedContentEntity.type.toString()), method)
+ .columns.get(columnName)!!.isNullable
+ ) {
+ errorReporter.reportError(
+ nullableUpdateParamForNonNullableEntityColumn(
+ param.simpleName.toString(), columnName,
+ resolvedContentEntity.type.toString()
+ ),
+ method
+ )
} else {
contentValues.add(Pair(columnName, param.simpleName.toString()))
}
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/Errors.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/Errors.kt
index 8b6d56e..72220ae 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/Errors.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/Errors.kt
@@ -22,78 +22,78 @@
fun missingEntityPrimaryKeyErrorMessage(entityName: String): String {
return "Content entity $entityName doesn't have a primary key, a content entity must have one" +
- " field annotated with @ContentPrimaryKey."
+ " field annotated with @ContentPrimaryKey."
}
fun missingFieldsInContentEntityErrorMessage(entityName: String): String {
return "Content entity $entityName has no fields, a content entity must have at least one " +
- "field and exactly one primary key."
+ "field and exactly one primary key."
}
fun missingAnnotationOnEntityFieldErrorMessage(fieldName: String, entityName: String): String {
return "Field $fieldName in $entityName is neither annotated with @ContentPrimaryKey nor " +
- "with @ContentColumn, all fields in a content entity must be be annotated by one of " +
- "the two"
+ "with @ContentColumn, all fields in a content entity must be be annotated by one of " +
+ "the two"
}
fun entityFieldWithBothAnnotations(columnName: String, entityName: String): String {
return "Field $columnName in $entityName is annotated with both @ContentPrimaryKey and " +
- "@ContentColumn, these annotations are mutually exclusive and a field " +
- "can only be annotated by one of the two."
+ "@ContentColumn, these annotations are mutually exclusive and a field " +
+ "can only be annotated by one of the two."
}
fun entityWithMultiplePrimaryKeys(entityName: String): String {
return "Content entity $entityName has two or more " +
- "primary keys, a content entity must have exactly one field annotated with " +
- "@ContentPrimaryKey."
+ "primary keys, a content entity must have exactly one field annotated with " +
+ "@ContentPrimaryKey."
}
fun unsupportedColumnType(columnName: String, entityName: String, type: String): String {
return "Field $columnName in $entityName is of type " +
- "$type which is not a supported column type."
+ "$type which is not a supported column type."
}
fun nonInstantiableEntity(entityName: String): String {
return "Entity $entityName is not instantiable. It has no non private non ignored " +
- "constructors, it must have one and only one such constructor, whether parametrized " +
- "or not."
+ "constructors, it must have one and only one such constructor, whether parametrized " +
+ "or not."
}
fun entityWithMultipleConstructors(entityName: String): String {
return "Entity $entityName has more than one non private non ignored constructor. Entities " +
- "should have only one non private non ignored constructor."
+ "should have only one non private non ignored constructor."
}
fun entityWithNullablePrimitiveType(fieldName: String, entityName: String): String {
return "Field $fieldName of entity $entityName is of a primitive type but is marked as " +
- "nullable. Please use the boxed type instead of the primitive of type for nullable " +
- "fields"
+ "nullable. Please use the boxed type instead of the primitive of type for nullable " +
+ "fields"
}
fun missingEntityOnMethod(methodName: String): String {
return "Method $methodName has no associated entity, " +
- "please ensure that either the content access object containing the method " +
- "specifies an entity inside the @ContentAccessObject annotation or that the " +
- "method specifies a content entity through the contentEntity parameter of " +
- "the annotation."
+ "please ensure that either the content access object containing the method " +
+ "specifies an entity inside the @ContentAccessObject annotation or that the " +
+ "method specifies a content entity through the contentEntity parameter of " +
+ "the annotation."
}
fun missingUriOnMethod(): String {
return "Failed to determine URI for query, the " +
- "URI is neither specified in the associated ContentEntity, nor in the annotation " +
- "parameters."
+ "URI is neither specified in the associated ContentEntity, nor in the annotation " +
+ "parameters."
}
fun badlyFormulatedOrderBy(orderByMember: String): String {
return "orderBy member \"$orderByMember\" is either not " +
- "properly formulated or references columns that are not in the " +
- "associated entity. All members in the orderBy array should either be" +
- " a column name or a column name following by \"asc\" or \"desc\""
+ "properly formulated or references columns that are not in the " +
+ "associated entity. All members in the orderBy array should either be" +
+ " a column name or a column name following by \"asc\" or \"desc\""
}
fun queriedColumnInProjectionNotInEntity(queriedColumn: String, entity: String): String {
return "Column $queriedColumn being queried through the projection is not defined within the " +
- "specified entity $entity."
+ "specified entity $entity."
}
fun queriedColumnInProjectionTypeDoesntMatchReturnType(
@@ -102,24 +102,24 @@
queriedColumn: String
): String {
return "Return type $returnType does not match type" +
- " $queriedColumnType of column $queriedColumn being queried."
+ " $queriedColumnType of column $queriedColumn being queried."
}
fun pojoHasMoreThanOneQualifyingConstructor(pojo: String): String {
return "Pojo $pojo has more than one non private" +
- " constructor. Pojos should have only one non private constructor."
+ " constructor. Pojos should have only one non private constructor."
}
fun pojoIsNotInstantiable(pojo: String): String {
return "Pojo $pojo is not instantiable! It has no non private non ignored " +
- "constructors, it must have one and only one such constructor, whether " +
- "parametrized or not."
+ "constructors, it must have one and only one such constructor, whether " +
+ "parametrized or not."
}
fun pojoWithNullablePrimitive(fieldName: String, pojo: String): String {
return "Field $fieldName of pojo $pojo is of a primitive type but is marked as " +
- "nullable. Please use the boxed type instead of the primitive of type for nullable " +
- "fields"
+ "nullable. Please use the boxed type instead of the primitive of type for nullable " +
+ "fields"
}
fun pojoFieldNotInEntity(
@@ -130,21 +130,22 @@
entity: String
): String {
return "Field $fieldName of type $fieldType corresponding to content" +
- " provider column $columnName in object $pojo doesn't match a field with same " +
- "type and content column in content entity $entity"
+ " provider column $columnName in object $pojo doesn't match a field with same " +
+ "type and content column in content entity $entity"
}
fun constructorFieldNotIncludedInProjectionNotNullable(fieldName: String, returnType: String):
- String {
- return "Field $fieldName in return object constructor $returnType is not included in the" +
+ String {
+ return "Field $fieldName in return object constructor $returnType is not included in the" +
" supplied projection and is not nullable. Constructor fields that are not" +
" included in a query projection should all be nullable."
-}
+ }
fun columnInProjectionNotIncludedInReturnPojo(columnName: String, returnType: String):
- String {
- return "Column $columnName in projection array isn't included in the return type $returnType"
-}
+ String {
+ return "Column $columnName in projection array isn't included in " +
+ "the return type $returnType"
+ }
fun nullableEntityColumnNotNullableInPojo(
fieldName: String,
@@ -153,15 +154,15 @@
entity: String
): String {
return "Field $fieldName of type $fieldType corresponding to content provider column " +
- "$columnName is not nullable, however that column is declared as nullable in the " +
- "associated entity $entity. Please mark the field as nullable."
+ "$columnName is not nullable, however that column is declared as nullable in the " +
+ "associated entity $entity. Please mark the field as nullable."
}
fun columnOnlyAsUri(): String = ": is an invalid uri, please follow it up with the parameter name"
fun missingUriParameter(parameterName: String): String {
return "Parameter $parameterName mentioned as the uri does not exist! Please add it to " +
- "the method parameters"
+ "the method parameters"
}
fun uriParameterIsNotString(parameterName: String): String {
@@ -176,7 +177,7 @@
fun columnInSelectionMissingFromEntity(columnName: String, entity: String): String {
return "Column $columnName in selection/where parameter" +
- " does not exist in content entity $entity"
+ " does not exist in content entity $entity"
}
fun columnInContentUpdateParametersNotInEntity(
@@ -185,33 +186,33 @@
entity: String
): String {
return "Parameter $paramName is annotated with @ContentColumn and specifies that it should " +
- "update column $columnName, however that column was not found in content entity $entity"
+ "update column $columnName, however that column was not found in content entity $entity"
}
fun mismatchedColumnTypeForColumnToBeUpdated(
paramName: String,
columnName: String,
paramType:
- String,
+ String,
entityType: String,
columnType: String
): String {
return "Parameter $paramName linked to column " +
- "$columnName is of type $paramType however that column's type " +
- "as specified by entity $entityType is $columnType"
+ "$columnName is of type $paramType however that column's type " +
+ "as specified by entity $entityType is $columnType"
}
fun methodSpecifiesWhereClauseWhenUpdatingUsingEntity(paramName: String): String {
return "@ContentUpdate annotated method specifies an entity as" +
- " parameter $paramName but also specifies a where clause. " +
- "Updates using an entity happen by matching the primary key and do not " +
- "take into consideration the where clause."
+ " parameter $paramName but also specifies a where clause. " +
+ "Updates using an entity happen by matching the primary key and do not " +
+ "take into consideration the where clause."
}
fun updatingMultipleEntitiesAtTheSameType(entityType: String, methodName: String): String {
return "There is more than one parameter of the entity type " +
- "$entityType to the @ContentUpdate annotated method" +
- " $methodName. Only one entity can be update at a time."
+ "$entityType to the @ContentUpdate annotated method" +
+ " $methodName. Only one entity can be update at a time."
}
fun contentUpdateAnnotatedMethodNotReturningAnInteger(): String {
@@ -228,23 +229,23 @@
fun insertMethodHasMoreThanOneEntity(): String {
return "@ContentInsert annotated method has more than one content entity in its parameters." +
- " @ContentInsert annotated methods parameters should include one and only one " +
- "content entity parameter (@ContentEntity annotated object)."
+ " @ContentInsert annotated methods parameters should include one and only one " +
+ "content entity parameter (@ContentEntity annotated object)."
}
fun insertMethodHasNoEntityInParameters(): String {
return "@ContentInsert annotated method has no entity parameters. @ContentInsert annotated " +
- "methods parameters should include one and only one content entity parameter " +
- "(@ContentEntity annotated object)."
+ "methods parameters should include one and only one content entity parameter " +
+ "(@ContentEntity annotated object)."
}
fun unsureWhatToUpdate(): String {
return "Not sure what this @ContentUpdate annotated method is supposed" +
- " to update, @ContentUpdate annotated methods should either specify a parameter " +
- "of the entity's type which will update the existing row in the content provider " +
- "using info from the entity object and will match on the primary key, or specify " +
- "one or more parameters annotated with @ContentColumn which will result in updating" +
- " rows matching any given criteria in the where clause to the specified values"
+ " to update, @ContentUpdate annotated methods should either specify a parameter " +
+ "of the entity's type which will update the existing row in the content provider " +
+ "using info from the entity object and will match on the primary key, or specify " +
+ "one or more parameters annotated with @ContentColumn which will result in updating" +
+ " rows matching any given criteria in the where clause to the specified values"
}
fun nullableUpdateParamForNonNullableEntityColumn(
@@ -253,10 +254,10 @@
entity: String
): String {
return "Parameter $paramName corresponding content column $columnName is nullable, however " +
- "that column is specified as non nullable in entity $entity. Please ensure that " +
- "parameter $paramName is non nullable too."
+ "that column is specified as non nullable in entity $entity. Please ensure that " +
+ "parameter $paramName is non nullable too."
}
fun ProcessingEnvironment.warn(warning: String, element: Element) {
this.messager.printMessage(Diagnostic.Kind.WARNING, warning, element)
-}
\ No newline at end of file
+}
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessor.kt
index ef47c95..7e440f1 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessor.kt
@@ -43,18 +43,21 @@
val selectionsArgs = ArrayList<String>()
val wordsStartingWithColumn = findWordsStartingWithColumn(selection)
for (wordStartingWithColumn in wordsStartingWithColumn) {
- if (wordStartingWithColumn.length == 1) {
- errorReporter.reportError(strayColumnInSelectionErrorMessage(), method)
- return null
- }
- val strippedParamName = wordStartingWithColumn.substring(1)
- if (!paramsNamesAndTypes.containsKey(strippedParamName)) {
- errorReporter.reportError(selectionParameterNotInMethodParameters
- (strippedParamName), method)
- return null
- }
- selectionsArgs.add(strippedParamName)
- modifiedSelection = modifiedSelection.replaceFirst(wordStartingWithColumn, "?")
+ if (wordStartingWithColumn.length == 1) {
+ errorReporter.reportError(strayColumnInSelectionErrorMessage(), method)
+ return null
+ }
+ val strippedParamName = wordStartingWithColumn.substring(1)
+ if (!paramsNamesAndTypes.containsKey(strippedParamName)) {
+ errorReporter.reportError(
+ selectionParameterNotInMethodParameters
+ (strippedParamName),
+ method
+ )
+ return null
+ }
+ selectionsArgs.add(strippedParamName)
+ modifiedSelection = modifiedSelection.replaceFirst(wordStartingWithColumn, "?")
}
val selectionExpression = CCJSqlParserUtil.parseCondExpression(modifiedSelection)
var foundMissingColumn = false
@@ -66,8 +69,13 @@
// around this for now.
if (!columnString.startsWith('"') || !columnString.endsWith('"')) {
if (!resolvedContentEntity.columns.contains(columnString)) {
- errorReporter.reportError(columnInSelectionMissingFromEntity(columnString,
- resolvedContentEntity.type.toString()), method)
+ errorReporter.reportError(
+ columnInSelectionMissingFromEntity(
+ columnString,
+ resolvedContentEntity.type.toString()
+ ),
+ method
+ )
foundMissingColumn = true
}
}
@@ -87,7 +95,8 @@
if (expression[currIndex] == ':') {
val startingIndex = currIndex
while (currIndex + 1 < expression.length && expression[currIndex + 1]
- .isLetterOrDigit()) {
+ .isLetterOrDigit()
+ ) {
currIndex++
}
wordsStartingWithColumn.add(expression.substring(startingIndex, currIndex + 1))
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/ErrorReporter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/ErrorReporter.kt
index 2504f3c..96ece18 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/ErrorReporter.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/ErrorReporter.kt
@@ -27,6 +27,7 @@
fun reportError(error: String, element: Element) {
errorReported = true
messager.printMessage(
- Diagnostic.Kind.ERROR, error, element)
+ Diagnostic.Kind.ERROR, error, element
+ )
}
}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/JvmSignatureUtil.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/JvmSignatureUtil.kt
index 182eb78..228e596 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/JvmSignatureUtil.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/JvmSignatureUtil.kt
@@ -261,10 +261,13 @@
val typeElement =
MoreElements.asType(element)
return when (typeElement.getNestingKind()) {
- NestingKind.TOP_LEVEL -> typeElement.getQualifiedName()
- .toString().replace('.', '/')
- NestingKind.MEMBER -> getInternalName(typeElement.getEnclosingElement
- ()) + "$" + typeElement.getSimpleName()
+ NestingKind.TOP_LEVEL ->
+ typeElement.getQualifiedName()
+ .toString().replace('.', '/')
+ NestingKind.MEMBER -> getInternalName(
+ typeElement.getEnclosingElement
+ ()
+ ) + "$" + typeElement.getSimpleName()
else -> throw IllegalArgumentException("Unsupported nesting kind.")
}
} catch (e: IllegalArgumentException) {
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentAccessObjectWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentAccessObjectWriter.kt
index a6097e0..5f4b88d 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentAccessObjectWriter.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentAccessObjectWriter.kt
@@ -38,22 +38,36 @@
val generatedClassName =
"${contentAccessObject.interfaceName.removePrefix(contentAccessObject.packageName)
.replace(".", "_")}Impl"
- val fileSpecBuilder = FileSpec.builder(contentAccessObject.packageName,
- generatedClassName)
+ val fileSpecBuilder = FileSpec.builder(
+ contentAccessObject.packageName,
+ generatedClassName
+ )
val contentResolverTypePlaceholder = ClassName("android.content", "ContentResolver")
- val coroutineDispatcherTypePlaceholder = ClassName("kotlinx.coroutines",
- "CoroutineDispatcher")
+ val coroutineDispatcherTypePlaceholder = ClassName(
+ "kotlinx.coroutines",
+ "CoroutineDispatcher"
+ )
val generatedClassBuilder = TypeSpec.classBuilder(generatedClassName)
.addSuperinterface(ClassName.bestGuess(contentAccessObject.interfaceName))
- .primaryConstructor(FunSpec.constructorBuilder()
- .addParameter("contentResolver", contentResolverTypePlaceholder)
- .addParameter("coroutineDispatcher", coroutineDispatcherTypePlaceholder)
- .build())
- .addProperty(PropertySpec.builder("_contentResolver",
- contentResolverTypePlaceholder).initializer("contentResolver").build())
- .addProperty(PropertySpec.builder("_coroutineDispatcher",
- coroutineDispatcherTypePlaceholder)
- .initializer("coroutineDispatcher").build())
+ .primaryConstructor(
+ FunSpec.constructorBuilder()
+ .addParameter("contentResolver", contentResolverTypePlaceholder)
+ .addParameter("coroutineDispatcher", coroutineDispatcherTypePlaceholder)
+ .build()
+ )
+ .addProperty(
+ PropertySpec.builder(
+ "_contentResolver",
+ contentResolverTypePlaceholder
+ ).initializer("contentResolver").build()
+ )
+ .addProperty(
+ PropertySpec.builder(
+ "_coroutineDispatcher",
+ coroutineDispatcherTypePlaceholder
+ )
+ .initializer("coroutineDispatcher").build()
+ )
for (contentQuery in contentAccessObject.queries) {
generatedClassBuilder.addFunction(
@@ -82,18 +96,20 @@
)
}
- val accessorFile = fileSpecBuilder.addType(generatedClassBuilder.addOriginatingElement
- (contentAccessObject.interfaceElement).build()).build()
+ val accessorFile = fileSpecBuilder.addType(
+ generatedClassBuilder.addOriginatingElement
+ (contentAccessObject.interfaceElement).build()
+ ).build()
accessorFile.writeTo(processingEnv.filer)
}
}
@KotlinPoetMetadataPreview
fun funSpecOverriding(element: ExecutableElement, processingEnv: ProcessingEnvironment):
- FunSpec.Builder {
- val builder = element.getKotlinFunspec(processingEnv).toBuilder()
- builder.modifiers.remove(KModifier.ABSTRACT)
- builder.annotations.removeAll { true }
- builder.addModifiers(KModifier.OVERRIDE)
- return builder
-}
\ No newline at end of file
+ FunSpec.Builder {
+ val builder = element.getKotlinFunspec(processingEnv).toBuilder()
+ builder.modifiers.remove(KModifier.ABSTRACT)
+ builder.annotations.removeAll { true }
+ builder.addModifiers(KModifier.OVERRIDE)
+ return builder
+ }
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentInsertMethodWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentInsertMethodWriter.kt
index 35b35ad..4ccdaa9 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentInsertMethodWriter.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentInsertMethodWriter.kt
@@ -36,7 +36,8 @@
fun createContentDeleteMethod(): FunSpec {
val methodBuilder = funSpecOverriding(contentInsert.method, processingEnv)
methodBuilder.annotations.add(
- AnnotationSpec.builder(Suppress::class).addMember("%S", "DEPRECATION").build())
+ AnnotationSpec.builder(Suppress::class).addMember("%S", "DEPRECATION").build()
+ )
if (contentInsert.isSuspend) {
val withContext = MemberName("kotlinx.coroutines", "withContext")
methodBuilder.beginControlFlow("return %M(_coroutineDispatcher)", withContext)
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentQueryMethodWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentQueryMethodWriter.kt
index 6793175..031bb0d 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentQueryMethodWriter.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentQueryMethodWriter.kt
@@ -51,9 +51,13 @@
fun createContentQueryMethod(): FunSpec? {
val uriTypePlaceHolder = ClassName("android.net", "Uri")
val methodBuilder = funSpecOverriding(contentQuery.method, processingEnv)
- methodBuilder.annotations.add(AnnotationSpec.builder(Suppress::class).addMember
- ("%S", "USELESS_CAST").addMember("%S", "UNCHECKED_CAST").addMember("%S",
- "PLATFORM_CLASS_MAPPED_TO_KOTLIN").addMember("%S", "DEPRECATION").build())
+ methodBuilder.annotations.add(
+ AnnotationSpec.builder(Suppress::class).addMember
+ ("%S", "USELESS_CAST").addMember("%S", "UNCHECKED_CAST").addMember(
+ "%S",
+ "PLATFORM_CLASS_MAPPED_TO_KOTLIN"
+ ).addMember("%S", "DEPRECATION").build()
+ )
if (contentQuery.isSuspend) {
val withContext = MemberName("kotlinx.coroutines", "withContext")
methodBuilder.beginControlFlow(
@@ -62,17 +66,23 @@
)
}
if (contentQuery.uri.startsWith(":")) {
- methodBuilder.addStatement("val _uri = %T.parse(%L)", uriTypePlaceHolder.copy(),
- contentQuery.uri.removePrefix(":"))
+ methodBuilder.addStatement(
+ "val _uri = %T.parse(%L)", uriTypePlaceHolder.copy(),
+ contentQuery.uri.removePrefix(":")
+ )
} else {
- methodBuilder.addStatement("val _uri = %T.parse(%S)", uriTypePlaceHolder.copy(),
- contentQuery.uri)
+ methodBuilder.addStatement(
+ "val _uri = %T.parse(%S)", uriTypePlaceHolder.copy(),
+ contentQuery.uri
+ )
}
methodBuilder.addStatement("val _projectionList = mutableListOf<String>()")
for (column in contentQuery.toQueryFor) {
if (column.requiresApi != null) {
- methodBuilder.beginControlFlow("if (%T.VERSION.SDK_INT >= ${column.requiresApi})",
- buildClassPlaceHolder)
+ methodBuilder.beginControlFlow(
+ "if (%T.VERSION.SDK_INT >= ${column.requiresApi})",
+ buildClassPlaceHolder
+ )
methodBuilder.addStatement("_projectionList.add(%S)", column.columnName)
methodBuilder.endControlFlow()
} else {
@@ -96,8 +106,10 @@
} else {
methodBuilder.addStatement("val _selection = \"\"")
}
- callResolverAndFormulateReturn(methodBuilder, contentQuery.returnType,
- noSelectionArgs)
+ callResolverAndFormulateReturn(
+ methodBuilder, contentQuery.returnType,
+ noSelectionArgs
+ )
if (contentQuery.isSuspend) {
methodBuilder.endControlFlow()
@@ -110,25 +122,36 @@
returnType: TypeMirror,
noSelectionArgs: Boolean
) {
- methodBuilder.addStatement("val _cursor = _contentResolver.query(_uri, _projection, " +
+ methodBuilder.addStatement(
+ "val _cursor = _contentResolver.query(_uri, _projection, " +
"_selection, ${if (noSelectionArgs) "null" else "_selectionArgs"}, %S)",
- contentQuery.orderBy)
+ contentQuery.orderBy
+ )
methodBuilder.beginControlFlow("if (_cursor == null)")
- methodBuilder.addStatement("throw NullPointerException(%S)", "Cursor returned by the " +
- "content provider was null!")
+ methodBuilder.addStatement(
+ "throw NullPointerException(%S)",
+ "Cursor returned by the " +
+ "content provider was null!"
+ )
methodBuilder.endControlFlow()
if (returnType.isSupportedGenericType()) {
val realReturnType = returnType.extractIntendedReturnType()
val returnTypeInKotlin = methodBuilder.build().returnType.toString()
if (returnType.isOptional()) {
- populateAndReturnOptionalFromCursor(methodBuilder, realReturnType,
- checkIfTypeArgumentIsNullable(returnTypeInKotlin))
+ populateAndReturnOptionalFromCursor(
+ methodBuilder, realReturnType,
+ checkIfTypeArgumentIsNullable(returnTypeInKotlin)
+ )
} else if (returnType.isList()) {
- populateAndReturnListFromCursor(methodBuilder, realReturnType,
- checkIfTypeArgumentIsNullable(returnTypeInKotlin))
+ populateAndReturnListFromCursor(
+ methodBuilder, realReturnType,
+ checkIfTypeArgumentIsNullable(returnTypeInKotlin)
+ )
} else if (returnType.isSet()) {
- populateAndReturnSetFromCursor(methodBuilder, realReturnType,
- checkIfTypeArgumentIsNullable(returnTypeInKotlin))
+ populateAndReturnSetFromCursor(
+ methodBuilder, realReturnType,
+ checkIfTypeArgumentIsNullable(returnTypeInKotlin)
+ )
}
} else {
returnNonPojoTypeFromCursor(methodBuilder, returnType)
@@ -140,9 +163,13 @@
realReturnType: TypeMirror,
typeArgumentIsNullable: Boolean
) {
- methodBuilder.addStatement("val _returnList = %T()",
- ClassName("kotlin.collections", "ArrayList").parameterizedBy(realReturnType
- .toKotlinClassName().copy(typeArgumentIsNullable)))
+ methodBuilder.addStatement(
+ "val _returnList = %T()",
+ ClassName("kotlin.collections", "ArrayList").parameterizedBy(
+ realReturnType
+ .toKotlinClassName().copy(typeArgumentIsNullable)
+ )
+ )
methodBuilder.beginControlFlow("while (_cursor.moveToNext())")
createReturnTypeFromCursor(realReturnType, methodBuilder, contentQuery.toQueryFor)
// Check !realReturnType.isSupportedColumnType() because POJOs cannot be null, their
@@ -150,19 +177,25 @@
// type is a supported cursor type (long, int, String etc...) Same goes for other
// collections.
if (typeArgumentIsNullable || !realReturnType.isSupportedColumnType()) {
- methodBuilder.addStatement("_returnList.add($RETURN_OBJECT_NAME as %T)",
+ methodBuilder.addStatement(
+ "_returnList.add($RETURN_OBJECT_NAME as %T)",
realReturnType
- .toKotlinClassName())
+ .toKotlinClassName()
+ )
} else {
methodBuilder.beginControlFlow("if ($RETURN_OBJECT_NAME != null)")
- methodBuilder.addStatement("_returnList.add($RETURN_OBJECT_NAME as %T)",
+ methodBuilder.addStatement(
+ "_returnList.add($RETURN_OBJECT_NAME as %T)",
realReturnType
- .toKotlinClassName())
+ .toKotlinClassName()
+ )
methodBuilder.endControlFlow()
}
methodBuilder.endControlFlow()
- methodBuilder.addStatement("$returnOrSet _returnList.toList() as ${methodBuilder.build()
- .returnType}")
+ methodBuilder.addStatement(
+ "$returnOrSet _returnList.toList() as ${methodBuilder.build()
+ .returnType}"
+ )
}
fun populateAndReturnSetFromCursor(
@@ -170,24 +203,34 @@
realReturnType: TypeMirror,
typeArgumentIsNullable: Boolean
) {
- methodBuilder.addStatement("val _returnSet = %T()",
- ClassName("kotlin.collections", "HashSet").parameterizedBy(realReturnType
- .toKotlinClassName().copy(typeArgumentIsNullable)).copy())
+ methodBuilder.addStatement(
+ "val _returnSet = %T()",
+ ClassName("kotlin.collections", "HashSet").parameterizedBy(
+ realReturnType
+ .toKotlinClassName().copy(typeArgumentIsNullable)
+ ).copy()
+ )
methodBuilder.beginControlFlow("while (_cursor.moveToNext())")
createReturnTypeFromCursor(realReturnType, methodBuilder, contentQuery.toQueryFor)
if (typeArgumentIsNullable || !realReturnType.isSupportedColumnType()) {
- methodBuilder.addStatement("_returnSet.add($RETURN_OBJECT_NAME as %T)",
- realReturnType.toKotlinClassName())
+ methodBuilder.addStatement(
+ "_returnSet.add($RETURN_OBJECT_NAME as %T)",
+ realReturnType.toKotlinClassName()
+ )
} else {
methodBuilder.beginControlFlow("if ($RETURN_OBJECT_NAME != null)")
- methodBuilder.addStatement("_returnSet.add($RETURN_OBJECT_NAME as %T)",
- realReturnType.toKotlinClassName())
+ methodBuilder.addStatement(
+ "_returnSet.add($RETURN_OBJECT_NAME as %T)",
+ realReturnType.toKotlinClassName()
+ )
methodBuilder.endControlFlow()
}
methodBuilder.endControlFlow()
- methodBuilder.addStatement("$returnOrSet _returnSet.toSet() as ${methodBuilder.build()
- .returnType}")
+ methodBuilder.addStatement(
+ "$returnOrSet _returnSet.toSet() as ${methodBuilder.build()
+ .returnType}"
+ )
}
fun populateAndReturnOptionalFromCursor(
@@ -196,19 +239,26 @@
typeArgumentIsNullable: Boolean
) {
if (typeArgumentIsNullable) {
- processingEnv.warn("Type argument $realReturnType of java.util.Optional is marked as " +
+ processingEnv.warn(
+ "Type argument $realReturnType of java.util.Optional is marked as " +
"nullable, an Optional cannot contain a null reference, instead it will be " +
- "empty.", contentQuery.method)
+ "empty.",
+ contentQuery.method
+ )
}
methodBuilder.beginControlFlow("if (_cursor.moveToNext())")
createReturnTypeFromCursor(realReturnType, methodBuilder, contentQuery.toQueryFor)
- methodBuilder.addStatement("$returnOrSet %T.ofNullable($RETURN_OBJECT_NAME as %T) as %L",
+ methodBuilder.addStatement(
+ "$returnOrSet %T.ofNullable($RETURN_OBJECT_NAME as %T) as %L",
ClassName("java.util", "Optional").copy(), realReturnType.toKotlinClassName(),
- methodBuilder.build().returnType.toString())
+ methodBuilder.build().returnType.toString()
+ )
methodBuilder.nextControlFlow("else")
- .addStatement("$returnOrSet Optional.empty<%T>() as %L",
+ .addStatement(
+ "$returnOrSet Optional.empty<%T>() as %L",
realReturnType.toKotlinClassName(),
- methodBuilder.build().returnType.toString())
+ methodBuilder.build().returnType.toString()
+ )
.endControlFlow()
}
@@ -218,8 +268,10 @@
) {
methodBuilder.beginControlFlow("if (_cursor.moveToNext())")
createReturnTypeFromCursor(returnType, methodBuilder, contentQuery.toQueryFor)
- methodBuilder.addStatement("$returnOrSet $RETURN_OBJECT_NAME as ${methodBuilder.build()
- .returnType}")
+ methodBuilder.addStatement(
+ "$returnOrSet $RETURN_OBJECT_NAME as ${methodBuilder.build()
+ .returnType}"
+ )
methodBuilder.nextControlFlow("else")
.addStatement("$returnOrSet null")
.endControlFlow()
@@ -250,29 +302,42 @@
for (column in columns) {
if (column.isNullable) {
if (column.requiresApi != null) {
- methodBuilder.beginControlFlow("val _${pojoColumnsToFieldNames
- .get(column.columnName)}_value = if (%T.VERSION.SDK_INT >= ${column
- .requiresApi})", buildClassPlaceHolder)
- methodBuilder.beginControlFlow("if (_cursor.isNull(_cursor" +
- ".getColumnIndex(%S)))", column.columnName)
+ methodBuilder.beginControlFlow(
+ "val _${pojoColumnsToFieldNames
+ .get(column.columnName)}_value = if (%T.VERSION.SDK_INT >= ${column
+ .requiresApi})",
+ buildClassPlaceHolder
+ )
+ methodBuilder.beginControlFlow(
+ "if (_cursor.isNull(_cursor" +
+ ".getColumnIndex(%S)))",
+ column.columnName
+ )
methodBuilder.addStatement("null")
methodBuilder.nextControlFlow("else")
- methodBuilder.addStatement("_cursor" +
+ methodBuilder.addStatement(
+ "_cursor" +
".${column.type.getCursorMethod()}(_cursor.getColumnIndex(%S))",
- column.columnName)
+ column.columnName
+ )
methodBuilder.endControlFlow()
methodBuilder.nextControlFlow("else")
methodBuilder.addStatement("null")
methodBuilder.endControlFlow()
} else {
- methodBuilder.beginControlFlow("val _${pojoColumnsToFieldNames
- .get(column.columnName)}_value = if (_cursor.isNull(_cursor" +
- ".getColumnIndex(%S)))", column.columnName)
+ methodBuilder.beginControlFlow(
+ "val _${pojoColumnsToFieldNames
+ .get(column.columnName)}_value = if (_cursor.isNull(_cursor" +
+ ".getColumnIndex(%S)))",
+ column.columnName
+ )
methodBuilder.addStatement("null")
methodBuilder.nextControlFlow("else")
- methodBuilder.addStatement("_cursor" +
+ methodBuilder.addStatement(
+ "_cursor" +
".${column.type.getCursorMethod()}(_cursor.getColumnIndex(%S))",
- column.columnName)
+ column.columnName
+ )
methodBuilder.endControlFlow()
}
} else {
@@ -280,21 +345,32 @@
// fields that were added in a later API to the provider. If that ever happens
// the bug ought to be with the entity or if it's legitimate then weird but
// okay, warrants a special exception.
- methodBuilder.beginControlFlow("val _${pojoColumnsToFieldNames.get(column
- .columnName)}_value" +
+ methodBuilder.beginControlFlow(
+ "val _${pojoColumnsToFieldNames.get(
+ column
+ .columnName
+ )}_value" +
" = if (_cursor.isNull(_cursor.getColumnIndex(%S)))",
- column.columnName)
- methodBuilder.addStatement("throw NullPointerException(%S)", "Column ${column
- .columnName} associated with field ${column.name} in $realReturnType " +
- "return null, however field ${column.name} is not nullable")
+ column.columnName
+ )
+ methodBuilder.addStatement(
+ "throw NullPointerException(%S)",
+ "Column ${column
+ .columnName} associated with field ${column.name} in $realReturnType " +
+ "return null, however field ${column.name} is not nullable"
+ )
methodBuilder.nextControlFlow("else")
- methodBuilder.addStatement("_cursor" +
+ methodBuilder.addStatement(
+ "_cursor" +
".${column.type.getCursorMethod()}(_cursor.getColumnIndex(%S))",
- column.columnName)
+ column.columnName
+ )
methodBuilder.endControlFlow()
}
- fieldNameValueMap.put(pojoColumnsToFieldNames.get(column.columnName)!!,
- "_${pojoColumnsToFieldNames.get(column.columnName)!!}_value")
+ fieldNameValueMap.put(
+ pojoColumnsToFieldNames.get(column.columnName)!!,
+ "_${pojoColumnsToFieldNames.get(column.columnName)!!}_value"
+ )
}
for (field in constructorFieldNames) {
if (field in fieldNameValueMap) {
@@ -304,8 +380,10 @@
}
}
- methodBuilder.addStatement("val $RETURN_OBJECT_NAME = %T(%L)", realReturnType,
- constructorParams.joinToString(","))
+ methodBuilder.addStatement(
+ "val $RETURN_OBJECT_NAME = %T(%L)", realReturnType,
+ constructorParams.joinToString(",")
+ )
} else {
// We should instead assign to public fields directly.
methodBuilder.addStatement("val $RETURN_OBJECT_NAME = %T()", realReturnType)
@@ -316,34 +394,54 @@
"if (%T.VERSION.SDK_INT >= ${column.requiresApi})",
buildClassPlaceHolder
)
- methodBuilder.beginControlFlow("if (!_cursor.isNull(_cursor" +
- ".getColumnIndex(%S)))", column.columnName)
- methodBuilder.addStatement("$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
- .get(column.columnName)} =" +
+ methodBuilder.beginControlFlow(
+ "if (!_cursor.isNull(_cursor" +
+ ".getColumnIndex(%S)))",
+ column.columnName
+ )
+ methodBuilder.addStatement(
+ "$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
+ .get(column.columnName)} =" +
" _cursor.${column.type.getCursorMethod()}" +
- "(_cursor.getColumnIndex(%S))", column.columnName)
+ "(_cursor.getColumnIndex(%S))",
+ column.columnName
+ )
methodBuilder.endControlFlow()
methodBuilder.endControlFlow()
} else {
- methodBuilder.beginControlFlow("if (!_cursor.isNull(_cursor" +
- ".getColumnIndex(%S)))", column.columnName)
- methodBuilder.addStatement("$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
- .get(column.columnName)} =" +
+ methodBuilder.beginControlFlow(
+ "if (!_cursor.isNull(_cursor" +
+ ".getColumnIndex(%S)))",
+ column.columnName
+ )
+ methodBuilder.addStatement(
+ "$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
+ .get(column.columnName)} =" +
" _cursor.${column.type.getCursorMethod()}" +
- "(_cursor.getColumnIndex(%S))", column.columnName)
+ "(_cursor.getColumnIndex(%S))",
+ column.columnName
+ )
methodBuilder.endControlFlow()
}
} else {
- methodBuilder.beginControlFlow("if (_cursor.isNull(" +
- "_cursor.getColumnIndex(%S)))", column.columnName)
- methodBuilder.addStatement("throw NullPointerException(%S)", "Column ${column
- .columnName} associated with field ${column.name} in $realReturnType " +
- "return null, however field ${column.name} is not nullable")
+ methodBuilder.beginControlFlow(
+ "if (_cursor.isNull(" +
+ "_cursor.getColumnIndex(%S)))",
+ column.columnName
+ )
+ methodBuilder.addStatement(
+ "throw NullPointerException(%S)",
+ "Column ${column
+ .columnName} associated with field ${column.name} in $realReturnType " +
+ "return null, however field ${column.name} is not nullable"
+ )
methodBuilder.nextControlFlow("else")
- methodBuilder.addStatement("$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
- .get(column.columnName)} = " +
+ methodBuilder.addStatement(
+ "$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
+ .get(column.columnName)} = " +
"_cursor.${column.type.getCursorMethod()}(_cursor.getColumnIndex(%S))",
- column.columnName)
+ column.columnName
+ )
methodBuilder.endControlFlow()
}
}
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentUpdateMethodWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentUpdateMethodWriter.kt
index a21b067..fab312d 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentUpdateMethodWriter.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentUpdateMethodWriter.kt
@@ -37,8 +37,11 @@
val methodBuilder = funSpecOverriding(contentUpdate.method, processingEnv)
methodBuilder.annotations.add(
AnnotationSpec.builder(Suppress::class).addMember
- ("%S", "USELESS_CAST").addMember("%S", "UNCHECKED_CAST").addMember("%S",
- "PLATFORM_CLASS_MAPPED_TO_KOTLIN").build())
+ ("%S", "USELESS_CAST").addMember("%S", "UNCHECKED_CAST").addMember(
+ "%S",
+ "PLATFORM_CLASS_MAPPED_TO_KOTLIN"
+ ).build()
+ )
if (contentUpdate.isSuspend) {
val withContext = MemberName("kotlinx.coroutines", "withContext")
methodBuilder.beginControlFlow(
@@ -47,14 +50,21 @@
)
}
if (contentUpdate.uri.startsWith(":")) {
- methodBuilder.addStatement("val _uri = %T.parse(%L)", uriTypePlaceHolder.copy(),
- contentUpdate.uri.removePrefix(":"))
+ methodBuilder.addStatement(
+ "val _uri = %T.parse(%L)", uriTypePlaceHolder.copy(),
+ contentUpdate.uri.removePrefix(":")
+ )
} else {
- methodBuilder.addStatement("val _uri = %T.parse(%S)", uriTypePlaceHolder.copy(),
- contentUpdate.uri)
+ methodBuilder.addStatement(
+ "val _uri = %T.parse(%S)", uriTypePlaceHolder.copy(),
+ contentUpdate.uri
+ )
}
- methodBuilder.addStatement("val _contentValues = %T(${contentUpdate.toUpdate
- .size})", contentValuesPlaceHolder)
+ methodBuilder.addStatement(
+ "val _contentValues = %T(${contentUpdate.toUpdate
+ .size})",
+ contentValuesPlaceHolder
+ )
for (value in contentUpdate.toUpdate) {
methodBuilder.addStatement("_contentValues.put(\"${value.first}\", ${value.second})")
}
@@ -74,8 +84,10 @@
} else {
methodBuilder.addStatement("val _where = \"\"")
}
- methodBuilder.addStatement("${returnOrSet}_contentResolver.update(_uri, _contentValues, " +
- "_where, ${if (noSelectionArgs) "null" else "_selectionArgs"})")
+ methodBuilder.addStatement(
+ "${returnOrSet}_contentResolver.update(_uri, _contentValues, " +
+ "_where, ${if (noSelectionArgs) "null" else "_selectionArgs"})"
+ )
if (contentUpdate.isSuspend) {
methodBuilder.endControlFlow()
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessorTest.kt
index d92a93a..18ea44b 100644
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessorTest.kt
+++ b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessorTest.kt
@@ -32,8 +32,10 @@
val entityName = "androidx.contentaccess.compiler.processor.test.Entity"
fun generateMainSourceFile(accessorBody: String, entityWithoutUri: Boolean = false):
- SourceFile {
- return SourceFile.kotlin("MyClass.kt", """
+ SourceFile {
+ return SourceFile.kotlin(
+ "MyClass.kt",
+ """
package androidx.contentaccess.compiler.processor.test
import androidx.contentaccess.ContentAccessObject
@@ -65,20 +67,22 @@
)
@ContentAccessObject(${if (entityWithoutUri) "EntityWithoutUri::class" else
- "Entity::class"})
+ "Entity::class"})
interface ContentAccessor {
$accessorBody
}
"""
- )
- }
+ )
+ }
@Test
fun validDelete() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentDelete
fun deleteAll(): Int
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -87,10 +91,13 @@
@Test
fun validDeleteWithUriLessEntity() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentDelete(uri = ":uri")
fun deleteUriLessEntity(uri: String): Int?
- """.trimIndent(), true)
+ """.trimIndent(),
+ true
+ )
val result = runCompilation(listOf(sourceFile))
@@ -99,10 +106,13 @@
@Test
fun checkThereIsAUriSomewhere() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentDelete
fun deleteWithNoUri(): Int?
- """.trimIndent(), true)
+ """.trimIndent(),
+ true
+ )
val result = runCompilation(listOf(sourceFile))
@@ -112,10 +122,12 @@
@Test
fun ensureContentEntityInAnnotationTakesPrecedence() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentDelete(contentEntity = EntityWithoutUri::class)
fun deleteAll(): Int?
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -127,10 +139,12 @@
@Test
fun ensureReturnsAnInt() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentDelete
fun deleteAll(): String?
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -142,10 +156,12 @@
@Test
fun ensureColumnsInWhereExist() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentDelete(where = "unknown_column = :param")
fun deleteAll(param: String): Int?
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessorTest.kt
index 6ff74c0..8f303ed 100644
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessorTest.kt
+++ b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessorTest.kt
@@ -38,7 +38,9 @@
val entityName = "androidx.contentaccess.compiler.processor.test.Entity"
fun generateMainSourceFile(entityCode: String = ""): SourceFile {
- return SourceFile.kotlin("MyClass.kt", """
+ return SourceFile.kotlin(
+ "MyClass.kt",
+ """
package androidx.contentaccess.compiler.processor.test
import androidx.contentaccess.ContentAccessObject
@@ -54,11 +56,14 @@
}
$entityCode
- """)
+ """
+ )
}
fun generateJavaEntity(entityBody: String): SourceFile {
- return SourceFile.java("Entity.java", """
+ return SourceFile.java(
+ "Entity.java",
+ """
package androidx.contentaccess.compiler.processor.test;
import org.jetbrains.annotations.Nullable;
@@ -71,18 +76,21 @@
public class Entity {
$entityBody
}
- """.trimIndent())
+ """.trimIndent()
+ )
}
@Test
fun validContentEntity() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentEntity("example.uri")
data class Entity(
@ContentPrimaryKey("_id") val id: Int,
@ContentColumn("a_random_long") val randomLong: Long
)
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -92,7 +100,8 @@
@Test
fun validJavaContentEntity() {
val mainSourceFile = generateMainSourceFile()
- val javaEntityFile = generateJavaEntity("""
+ val javaEntityFile = generateJavaEntity(
+ """
@ContentPrimaryKey(columnName = "_id")
public long eventId;
@@ -102,7 +111,8 @@
@ContentColumn(columnName = "dtend")
@Nullable
public Long endTime;
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(mainSourceFile, javaEntityFile))
@@ -111,13 +121,15 @@
@Test
fun ensureExistingContentPrimaryKey() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentEntity("example.uri")
data class Entity(
@ContentColumn("_id") val id: Int,
@ContentColumn("a_random_long") val randomLong: Long
)
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -127,10 +139,12 @@
@Test
fun ensureEntityContainsFields() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentEntity("example.uri")
data class Entity()
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -140,12 +154,14 @@
@Test
fun ensureAllFieldsAreAnnotated() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentEntity("example.uri")
data class Entity(
val id: Int
)
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -156,7 +172,8 @@
@Test
fun ensureOnlyOneAnnotation() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentEntity("example.uri")
data class Entity(
@ContentPrimaryKey("_id")
@@ -164,7 +181,8 @@
val id: Int,
@ContentColumn("a_random_long") val randomLong: Long
)
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -175,13 +193,15 @@
@Test
fun ensureSupportedColumnType() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentEntity("example.uri")
data class Entity(
@ContentPrimaryKey("_id") val id: List<Long>,
@ContentColumn("a_random_long") val randomLong: Long
)
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -192,7 +212,8 @@
@Test
fun ensureSingleNonPrivateNonIgnoredConstructor() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentEntity("example.uri")
data class Entity(
@ContentPrimaryKey("_id") val id: Long,
@@ -200,7 +221,8 @@
) {
constructor(@ContentPrimaryKey("_id") id: Long) : this(id, null)
}
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -211,7 +233,8 @@
@Test
fun ensureInstantiableEntity() {
val mainSourceFile = generateMainSourceFile()
- val javaEntitySourceFile = generateJavaEntity("""
+ val javaEntitySourceFile = generateJavaEntity(
+ """
@ContentColumn(columnName = "_id")
public long eventId;
@@ -224,7 +247,8 @@
public Entity(int randomParameter) {}
private Entity() {}
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(mainSourceFile, javaEntitySourceFile))
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
@@ -234,19 +258,25 @@
@Test
fun ensureNonNullablePrimitives() {
val mainSourceFile = generateMainSourceFile()
- val javaEntitySourceFile = generateJavaEntity("""
+ val javaEntitySourceFile = generateJavaEntity(
+ """
@ContentPrimaryKey(columnName = "_id")
public long eventId;
@ContentColumn(columnName = "dtstart")
@Nullable
public long startTime;
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(mainSourceFile, javaEntitySourceFile))
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(entityWithNullablePrimitiveType("startTime",
- entityName))
+ assertThat(result.messages).contains(
+ entityWithNullablePrimitiveType(
+ "startTime",
+ entityName
+ )
+ )
}
}
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessorTest.kt
index 0376051..a1b2ce7b 100644
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessorTest.kt
+++ b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessorTest.kt
@@ -31,8 +31,10 @@
class ContentInsertProcessorTest {
fun generateMainSourceFile(accessorBody: String):
- SourceFile {
- return SourceFile.kotlin("MyClass.kt", """
+ SourceFile {
+ return SourceFile.kotlin(
+ "MyClass.kt",
+ """
package androidx.contentaccess.compiler.processor.test
import androidx.contentaccess.ContentAccessObject
@@ -69,15 +71,17 @@
$accessorBody
}
"""
- )
- }
+ )
+ }
@Test
fun validInsert() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentInsert
fun insertEntity(entity: Entity): Uri?
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -86,13 +90,15 @@
@Test
fun validInsertWithUriLessEntity() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentInsert(uri = ":uri")
fun insertUriLessEntity(
entity: EntityWithoutUri,
uri: String
): Uri?
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -101,10 +107,12 @@
@Test
fun checkThereIsAnEntityInParameters() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentInsert
fun insertWithNoEntity(randomNonEntityParam: String): Uri?
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -114,10 +122,12 @@
@Test
fun checkNoMoreThanOneEntityInParameters() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentInsert
fun insertMultipleEntities(entity1: Entity, entity2: Entity): Uri?
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -127,29 +137,35 @@
@Test
fun ensureReturnTypeIsUri() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentInsert
fun insertEntity(entity: Entity): Int?
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(contentInsertAnnotatedMethodNotReturningAUri()
+ assertThat(result.messages).contains(
+ contentInsertAnnotatedMethodNotReturningAUri()
)
}
@Test
fun ensureUriExists() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentInsert
fun insertEntity(entity: EntityWithoutUri): Int?
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(missingUriOnMethod()
+ assertThat(result.messages).contains(
+ missingUriOnMethod()
)
}
}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessorTest.kt
index 2d6bcea..2021d8f 100644
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessorTest.kt
+++ b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessorTest.kt
@@ -49,7 +49,9 @@
pojos: String = "",
withEntity: Boolean = true
): SourceFile {
- return SourceFile.kotlin("MyClass.kt", """
+ return SourceFile.kotlin(
+ "MyClass.kt",
+ """
package androidx.contentaccess.compiler.processor.test
import androidx.contentaccess.ContentAccessObject
@@ -90,7 +92,9 @@
}
fun generateJavaPojo(pojoBody: String): SourceFile {
- return SourceFile.java("Pojo.java", """
+ return SourceFile.java(
+ "Pojo.java",
+ """
package androidx.contentaccess.compiler.processor.test;
import org.jetbrains.annotations.Nullable;
@@ -101,12 +105,14 @@
public class Pojo {
$pojoBody
}
- """.trimIndent())
+ """.trimIndent()
+ )
}
@Test
fun validQueries() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery
fun getAllStartTimeDescriptionAnnotatedPojo(): List<StartTimeDescription2>
@@ -148,7 +154,8 @@
@ContentQuery
suspend fun getAllEntitiesSuspend(): List<EntityWithUri>
- """.trimIndent(), """
+ """.trimIndent(),
+ """
data class StartTimeDescription1(
@ContentColumn("dtstart") val startingTime: Long?,
@ContentColumn("description") val theDescription: String?
@@ -158,7 +165,8 @@
val dtstart: Long?,
val description: String?
)
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -167,10 +175,13 @@
@Test
fun checkExistingEntity() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery
fun getAll(): List<String>
- """.trimIndent(), withEntity = false)
+ """.trimIndent(),
+ withEntity = false
+ )
val result = runCompilation(listOf(sourceFile))
@@ -180,10 +191,12 @@
@Test
fun checkingExistingUri() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery(contentEntity = EntityWithoutUri::class)
fun getAll(): List<String>
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -193,10 +206,12 @@
@Test
fun missingOrderByColumn() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery(orderBy = arrayOf("nonExistingColumn"))
fun getAll(): List<String>
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -206,63 +221,81 @@
@Test
fun badlyFormulatedOrderBy() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery(orderBy = arrayOf("dtstart desc thisshouldntbehere"))
fun getAll(): List<String>
- """.trimIndent())
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(badlyFormulatedOrderBy("dtstart desc " +
- "thisshouldntbehere"))
- }
-
- @Test
- fun ensureExistingColumn() {
- val sourceFile = generateMainSourceFile("""
- @ContentQuery(projection = arrayOf("nonExisting"))
- fun getAll(): List<String>
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
assertThat(result.messages).contains(
- queriedColumnInProjectionNotInEntity("nonExisting",
- "androidx.contentaccess.compiler.processor.test.EntityWithUri")
+ badlyFormulatedOrderBy(
+ "dtstart desc " +
+ "thisshouldntbehere"
+ )
+ )
+ }
+
+ @Test
+ fun ensureExistingColumn() {
+ val sourceFile = generateMainSourceFile(
+ """
+ @ContentQuery(projection = arrayOf("nonExisting"))
+ fun getAll(): List<String>
+ """.trimIndent()
+ )
+
+ val result = runCompilation(listOf(sourceFile))
+
+ assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
+ assertThat(result.messages).contains(
+ queriedColumnInProjectionNotInEntity(
+ "nonExisting",
+ "androidx.contentaccess.compiler.processor.test.EntityWithUri"
+ )
)
}
@Test
fun ensureMatchingReturnTypeNonPojo() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery(projection = arrayOf("description"))
fun getAll(): Long
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
assertThat(result.messages).contains(
- queriedColumnInProjectionTypeDoesntMatchReturnType("long",
+ queriedColumnInProjectionTypeDoesntMatchReturnType(
+ "long",
"java.lang.String",
- "description")
+ "description"
+ )
)
}
@Test
// A "qualifying" constructor is a non private and non ignored constructor
fun ensurePojoHasNoMoreThanOneQualifyingConstructor() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery
fun getAll(): Pojo
- """.trimIndent())
- val javaPojoFile = generateJavaPojo("""
+ """.trimIndent()
+ )
+ val javaPojoFile = generateJavaPojo(
+ """
// Two public constructors
public Pojo() {}
public Pojo(int unused) {}
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile, javaPojoFile))
@@ -272,16 +305,20 @@
@Test
fun ensurePojoIsInstantiable() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery
fun getAll(): Pojo
- """.trimIndent())
- val javaPojoFile = generateJavaPojo("""
+ """.trimIndent()
+ )
+ val javaPojoFile = generateJavaPojo(
+ """
// Two public constructors
private Pojo() {}
@IgnoreConstructor
public Pojo(int unused) {}
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile, javaPojoFile))
@@ -291,14 +328,18 @@
@Test
fun ensurePojoDoesntHaveANullablePrimitive() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery
fun getAll(): Pojo
- """.trimIndent())
- val javaPojoFile = generateJavaPojo("""
+ """.trimIndent()
+ )
+ val javaPojoFile = generateJavaPojo(
+ """
@Nullable
public long dtstart;
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile, javaPojoFile))
@@ -308,66 +349,86 @@
@Test
fun ensurePojoFieldsMatchOnesInEntity() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery
fun getAll(): IncorrectPojo
- """.trimIndent(), """
+ """.trimIndent(),
+ """
data class IncorrectPojo(@ContentColumn("irrelevant_column")val irrelevantField: String)
- """.trimIndent())
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(pojoFieldNotInEntity("irrelevantField",
- "java.lang.String", "irrelevant_column",
- "androidx.contentaccess.compiler.processor.test.IncorrectPojo",
- entityName))
- }
-
- @Test
- fun ensureFieldsNotInProjectionButInConstructorAreNullable() {
- val sourceFile = generateMainSourceFile("""
- @ContentQuery(projection = arrayOf("dtstart"))
- fun getAll(): CustomPojo
- """.trimIndent(), """
- data class CustomPojo(val dtstart: Long?, val nonNullableField: Long)
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
assertThat(result.messages).contains(
- constructorFieldNotIncludedInProjectionNotNullable("nonNullableField",
- "androidx.contentaccess.compiler.processor.test.CustomPojo")
+ pojoFieldNotInEntity(
+ "irrelevantField",
+ "java.lang.String", "irrelevant_column",
+ "androidx.contentaccess.compiler.processor.test.IncorrectPojo",
+ entityName
+ )
+ )
+ }
+
+ @Test
+ fun ensureFieldsNotInProjectionButInConstructorAreNullable() {
+ val sourceFile = generateMainSourceFile(
+ """
+ @ContentQuery(projection = arrayOf("dtstart"))
+ fun getAll(): CustomPojo
+ """.trimIndent(),
+ """
+ data class CustomPojo(val dtstart: Long?, val nonNullableField: Long)
+ """.trimIndent()
+ )
+
+ val result = runCompilation(listOf(sourceFile))
+
+ assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
+ assertThat(result.messages).contains(
+ constructorFieldNotIncludedInProjectionNotNullable(
+ "nonNullableField",
+ "androidx.contentaccess.compiler.processor.test.CustomPojo"
+ )
)
}
@Test
fun ensurePojoContainsAllProjectionFields() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery(projection = arrayOf("dtstart", "description"))
fun getAll(): PojoMissingField
- """.trimIndent(), """
+ """.trimIndent(),
+ """
data class PojoMissingField(val dtstart: Long?)
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
assertThat(result.messages).contains(
- columnInProjectionNotIncludedInReturnPojo("description",
- "androidx.contentaccess.compiler.processor.test.PojoMissingField")
+ columnInProjectionNotIncludedInReturnPojo(
+ "description",
+ "androidx.contentaccess.compiler.processor.test.PojoMissingField"
+ )
)
}
@Test
fun ensureNullableEntityFieldsAreAlsoNullableInPojo() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery
fun getAll(): PojoWithNonNullableField
- """.trimIndent(), """
+ """.trimIndent(),
+ """
data class PojoWithNonNullableField(val dtstart: Long)
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -384,10 +445,12 @@
@Test
fun ensureUriParameterProperlySpecified() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery(uri = ":")
fun getAll(): List<EntityWithUri>
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -397,10 +460,12 @@
@Test
fun ensureUriParameterExists() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery(uri = ":param")
fun getAll(): List<EntityWithUri>
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -410,10 +475,12 @@
@Test
fun ensureUriParameterIsString() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery(uri = ":param")
fun getAll(param: Long): List<EntityWithUri>
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessorTest.kt
index b2182bc..5072e95 100644
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessorTest.kt
+++ b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessorTest.kt
@@ -36,8 +36,10 @@
val entityName = "androidx.contentaccess.compiler.processor.test.Entity"
fun generateMainSourceFile(accessorBody: String, entityWithoutUri: Boolean = false):
- SourceFile {
- return SourceFile.kotlin("MyClass.kt", """
+ SourceFile {
+ return SourceFile.kotlin(
+ "MyClass.kt",
+ """
package androidx.contentaccess.compiler.processor.test
import androidx.contentaccess.ContentAccessObject
@@ -69,17 +71,18 @@
)
@ContentAccessObject(${if (entityWithoutUri) "EntityWithoutUri::class" else
- "Entity::class"})
+ "Entity::class"})
interface ContentAccessor {
$accessorBody
}
"""
- )
- }
+ )
+ }
@Test
fun validUpdates() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentUpdate
fun updateDescription(@ContentColumn("description") desc: String): Int
@@ -90,7 +93,8 @@
id: Long,
uri: String
): Int
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -99,7 +103,8 @@
@Test
fun validUpdatesWithUriLessEntity() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentUpdate(where = "_id = 123", uri = ":uri")
fun updateDescriptionWithUri(
@ContentColumn("description") desc: String,
@@ -110,7 +115,9 @@
fun updateDescription(
@ContentColumn("description") desc: String
): Int
- """.trimIndent(), entityWithoutUri = true)
+ """.trimIndent(),
+ entityWithoutUri = true
+ )
val result = runCompilation(listOf(sourceFile))
@@ -119,40 +126,52 @@
@Test
fun checkColumnsExist() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentUpdate(where = "_id = :id")
fun updateDescription(@ContentColumn("nonexistent") desc: String, id: Long): Int
- """.trimIndent())
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(columnInContentUpdateParametersNotInEntity("desc",
- "nonexistent", entityName))
- }
-
- @Test
- fun ensureTypesMatch() {
- val sourceFile = generateMainSourceFile("""
- @ContentUpdate
- fun updateDescription(@ContentColumn("description") desc: Long): Int
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
assertThat(result.messages).contains(
- mismatchedColumnTypeForColumnToBeUpdated("desc",
- "description", "long", entityName, "java.lang.String")
+ columnInContentUpdateParametersNotInEntity(
+ "desc",
+ "nonexistent", entityName
+ )
+ )
+ }
+
+ @Test
+ fun ensureTypesMatch() {
+ val sourceFile = generateMainSourceFile(
+ """
+ @ContentUpdate
+ fun updateDescription(@ContentColumn("description") desc: Long): Int
+ """.trimIndent()
+ )
+
+ val result = runCompilation(listOf(sourceFile))
+
+ assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
+ assertThat(result.messages).contains(
+ mismatchedColumnTypeForColumnToBeUpdated(
+ "desc",
+ "description", "long", entityName, "java.lang.String"
+ )
)
}
@Test
fun ensureNoWhereClauseWhenUpdatingEntity() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentUpdate(where = "_id = 123")
fun updateDescription(entityParam: Entity): Int
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -164,10 +183,12 @@
@Test
fun ensureOnlyOneEntityIsUpdatedAtTheSameTime() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentUpdate
fun updateDescription(entityParam1: Entity, entityParam2: Entity): Int
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -179,10 +200,12 @@
@Test
fun ensureContentUpdateMethodReturnsAnInteger() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentUpdate
fun updateDescription(entityParam1: Entity): Long
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -192,10 +215,12 @@
@Test
fun ensureSomethingIsBeingUpdated() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentUpdate
fun updateDescription(entities: List<Entity>): Int
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -205,15 +230,19 @@
@Test
fun ensureNonNullableUpdateParametersForNonNullablEntityColumn() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentUpdate
fun updateDescription(@ContentColumn("dtend") newEndTime: Long?): Int
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(nullableUpdateParamForNonNullableEntityColumn
- ("newEndTime", "dtend", entityName))
+ assertThat(result.messages).contains(
+ nullableUpdateParamForNonNullableEntityColumn
+ ("newEndTime", "dtend", entityName)
+ )
}
}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessorTest.kt
index 202a018..449aaf5 100644
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessorTest.kt
+++ b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessorTest.kt
@@ -33,7 +33,9 @@
val entityName = "androidx.contentaccess.compiler.processor.test.Entity"
fun generateMainSourceFile(accessorBody: String): SourceFile {
- return SourceFile.kotlin("MyClass.kt", """
+ return SourceFile.kotlin(
+ "MyClass.kt",
+ """
package androidx.contentaccess.compiler.processor.test
import androidx.contentaccess.ContentAccessObject
@@ -62,11 +64,13 @@
@Test
fun validSelection() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery(selection = "dtstart > 1 OR (dtstart < 5 AND description = \"abc\")" +
" OR ((description = :parameter AND (dtstart * 6 = 30)))")
fun getAll(parameter: String): List<Entity>
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -75,10 +79,12 @@
@Test
fun ensureNoStraySelectionColumns() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery(selection = "dtstart = : AND description > :parameter")
fun getAll(parameter: String): List<Entity>
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -88,10 +94,12 @@
@Test
fun ensureSelectionArgumentsAreSpecifiedInParameter() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery(selection = "description > :parameter")
fun getAll(): List<Entity>
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
@@ -101,16 +109,19 @@
@Test
fun ensureColumnsMentionedInSelectionExistInEntity() {
- val sourceFile = generateMainSourceFile("""
+ val sourceFile = generateMainSourceFile(
+ """
@ContentQuery(selection = "unknown_column > 5")
fun getAll(): List<Entity>
- """.trimIndent())
+ """.trimIndent()
+ )
val result = runCompilation(listOf(sourceFile))
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
assertThat(result.messages).contains(
- columnInSelectionMissingFromEntity("unknown_column", entityName))
+ columnInSelectionMissingFromEntity("unknown_column", entityName)
+ )
}
@Test
diff --git a/contentaccess/contentaccess-entities/src/main/kotlin/androidx/contentaccess/entities/ContentAccessMediaStore.kt b/contentaccess/contentaccess-entities/src/main/kotlin/androidx/contentaccess/entities/ContentAccessMediaStore.kt
index 7148cdf..8ecc18a 100644
--- a/contentaccess/contentaccess-entities/src/main/kotlin/androidx/contentaccess/entities/ContentAccessMediaStore.kt
+++ b/contentaccess/contentaccess-entities/src/main/kotlin/androidx/contentaccess/entities/ContentAccessMediaStore.kt
@@ -54,9 +54,11 @@
public var _id: Int? = null
@JvmField
- @Deprecated("Apps may not have filesystem permissions to directly access this path. " +
+ @Deprecated(
+ "Apps may not have filesystem permissions to directly access this path. " +
"Instead of trying to open this path directly, apps should use " +
- "ContentResolver#openFileDescriptor(Uri, String) to gain access.")
+ "ContentResolver#openFileDescriptor(Uri, String) to gain access."
+ )
@ContentColumn(android.provider.MediaStore.MediaColumns.DATA)
public var data: String? = null
@@ -137,28 +139,36 @@
open class ImageColumns : MediaColumns() {
@JvmField
- @Deprecated("As of API 29, this value was only relevant for images hosted on Picasa, " +
- "which are no longer supported.")
+ @Deprecated(
+ "As of API 29, this value was only relevant for images hosted on Picasa, " +
+ "which are no longer supported."
+ )
@ContentColumn(android.provider.MediaStore.Images.ImageColumns.PICASA_ID)
public var picasaId: String? = null
@JvmField
- @Deprecated("As of API 29, location details are no longer indexed for privacy reasons, " +
+ @Deprecated(
+ "As of API 29, location details are no longer indexed for privacy reasons, " +
"and this value is now always null. You can still manually obtain location " +
- "metadata using ExifInterface#getLatLong(float[]).")
+ "metadata using ExifInterface#getLatLong(float[])."
+ )
@ContentColumn(android.provider.MediaStore.Images.ImageColumns.LATITUDE)
public var latitude: Float? = null
@JvmField
- @Deprecated("As of API 29, location details are no longer indexed for privacy reasons, " +
+ @Deprecated(
+ "As of API 29, location details are no longer indexed for privacy reasons, " +
"and this value is now always null. You can still manually obtain location " +
- "metadata using ExifInterface#getLatLong(float[]).")
+ "metadata using ExifInterface#getLatLong(float[])."
+ )
@ContentColumn(android.provider.MediaStore.Images.ImageColumns.LONGITUDE)
public var longitude: Float? = null
@JvmField
- @Deprecated("As of API 29, all thumbnails should be obtained via MediaStore.Images" +
- ".Thumbnails#getThumbnail, as this value is no longer supported.")
+ @Deprecated(
+ "As of API 29, all thumbnails should be obtained via MediaStore.Images" +
+ ".Thumbnails#getThumbnail, as this value is no longer supported."
+ )
@ContentColumn(android.provider.MediaStore.Images.ImageColumns.MINI_THUMB_MAGIC)
public var miniThumbMagic: Int? = null
@@ -252,9 +262,11 @@
public var _id: Int? = null
@JvmField
- @Deprecated("Deprecated in API 29. Apps may not have filesystem permissions to directly " +
+ @Deprecated(
+ "Deprecated in API 29. Apps may not have filesystem permissions to directly " +
"access this path. Instead of trying to open this path directly, apps should use " +
- "ContentResolver#loadThumbnail to gain access.")
+ "ContentResolver#loadThumbnail to gain access."
+ )
@ContentColumn(android.provider.MediaStore.Images.Thumbnails.DATA)
public var data: String? = null
@@ -275,8 +287,10 @@
public var height: Int? = null
}
- @Deprecated("Callers should migrate to using ContentResolver#loadThumbnail, since it offers " +
- "richer control over requested thumbnail sizes and cancellationbehavior.")
+ @Deprecated(
+ "Callers should migrate to using ContentResolver#loadThumbnail, since it offers " +
+ "richer control over requested thumbnail sizes and cancellationbehavior."
+ )
@ContentEntity("content://media/external/images/thumbnails")
class ImageThumbnail : ImageThumbnailColumns()
@@ -287,9 +301,11 @@
public var _id: Int? = null
@JvmField
- @Deprecated("Deprecated in API 29. Apps may not have filesystem permissions to directly " +
+ @Deprecated(
+ "Deprecated in API 29. Apps may not have filesystem permissions to directly " +
"access this path. Instead of trying to open this path directly, apps should use " +
- "ContentResolver#loadThumbnail to gain access.")
+ "ContentResolver#loadThumbnail to gain access."
+ )
@ContentColumn(android.provider.MediaStore.Video.Thumbnails.DATA)
public var data: String? = null
@@ -310,23 +326,29 @@
public var height: Int? = null
}
- @Deprecated("Callers should migrate to using ContentResolver#loadThumbnail, since it offers " +
- "richer control over requested thumbnail sizes and cancellationbehavior.")
+ @Deprecated(
+ "Callers should migrate to using ContentResolver#loadThumbnail, since it offers " +
+ "richer control over requested thumbnail sizes and cancellationbehavior."
+ )
@ContentEntity("content://media/external/video/thumbnails")
class VideoThumbnail : VideoThumbnailColumns()
open class VideoColumns : MediaColumns() {
@JvmField
- @Deprecated("As of API 29, location details are no longer indexed for privacy reasons, " +
+ @Deprecated(
+ "As of API 29, location details are no longer indexed for privacy reasons, " +
"and this value is now always null. You can still manually obtain location " +
- "metadata using ExifInterface#getLatLong(float[]).")
+ "metadata using ExifInterface#getLatLong(float[])."
+ )
@ContentColumn(android.provider.MediaStore.Video.VideoColumns.LATITUDE)
public var latitude: Float? = null
@JvmField
- @Deprecated("As of API 29, location details are no longer indexed for privacy reasons, " +
+ @Deprecated(
+ "As of API 29, location details are no longer indexed for privacy reasons, " +
"and this value is now always null. You can still manually obtain location " +
- "metadata using ExifInterface#getLatLong(float[]).")
+ "metadata using ExifInterface#getLatLong(float[])."
+ )
@ContentColumn(android.provider.MediaStore.Video.VideoColumns.LONGITUDE)
public var longitude: Float? = null
@@ -351,8 +373,10 @@
public var language: String? = null
@JvmField
- @Deprecated("As for API 29, all thumbnails should be obtained via MediaStore.Images" +
- ".Thumbnails#getThumbnail, as this value is no longer supported.")
+ @Deprecated(
+ "As for API 29, all thumbnails should be obtained via MediaStore.Images" +
+ ".Thumbnails#getThumbnail, as this value is no longer supported."
+ )
@ContentColumn(android.provider.MediaStore.Video.VideoColumns.MINI_THUMB_MAGIC)
public var miniThumbMagic: Int? = null
@@ -429,11 +453,13 @@
open class AudioColumns : MediaColumns() {
@JvmField
- @Deprecated("Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
+ @Deprecated(
+ "Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
"means they don't reflect locale-specific sorting preferences. To apply " +
"locale-specific sorting preferences, use " +
"ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE. ")
+ "ContentResolver#QUERY_ARG_SORT_LOCALE. "
+ )
@ContentColumn(android.provider.MediaStore.Audio.AudioColumns.TITLE_KEY)
public var titleKey: String? = null
@@ -446,11 +472,13 @@
public var artistId: Int? = null
@JvmField
- @Deprecated("Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
+ @Deprecated(
+ "Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
"means they don't reflect locale-specific sorting preferences. To apply " +
"locale-specific sorting preferences, use " +
"ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE. ")
+ "ContentResolver#QUERY_ARG_SORT_LOCALE. "
+ )
@ContentColumn(android.provider.MediaStore.Audio.AudioColumns.ARTIST_KEY)
public var artistKey: String? = null
@@ -459,11 +487,13 @@
public var albumId: Int? = null
@JvmField
- @Deprecated("Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
+ @Deprecated(
+ "Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
"means they don't reflect locale-specific sorting preferences. To apply " +
"locale-specific sorting preferences, use " +
"ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE. ")
+ "ContentResolver#QUERY_ARG_SORT_LOCALE. "
+ )
@ContentColumn(android.provider.MediaStore.Audio.AudioColumns.ALBUM_KEY)
public var albumKey: String? = null
@@ -506,11 +536,13 @@
public var genreId: Int? = null
@JvmField
- @Deprecated("Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
+ @Deprecated(
+ "Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
"means they don't reflect locale-specific sorting preferences. To apply " +
"locale-specific sorting preferences, use " +
"ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE. ")
+ "ContentResolver#QUERY_ARG_SORT_LOCALE. "
+ )
@RequiresApi(30)
@ContentColumn(android.provider.MediaStore.Audio.AudioColumns.GENRE_KEY)
public var genreKey: String? = null
@@ -581,9 +613,11 @@
public var album: String? = null
@JvmField
- @Deprecated("This constant was deprecated in API level 29. Apps may not have filesystem " +
+ @Deprecated(
+ "This constant was deprecated in API level 29. Apps may not have filesystem " +
"permissions to directly access this path. Instead of trying to open this path " +
- "directly, apps should use ContentResolver#loadThumbnail to gain access.")
+ "directly, apps should use ContentResolver#loadThumbnail to gain access."
+ )
@ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ALBUM_ART)
public var albumArt: String? = null
@@ -593,11 +627,13 @@
public var albumId: Int? = null
@JvmField
- @Deprecated("This constant was deprecated in API level 30. These keys are generated using" +
+ @Deprecated(
+ "This constant was deprecated in API level 30. These keys are generated using" +
" Locale.ROOT, which means they don't reflect locale-specific sorting preferences" +
". To apply locale-specific sorting preferences, use " +
"ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE.")
+ "ContentResolver#QUERY_ARG_SORT_LOCALE."
+ )
@ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ALBUM_KEY)
public var albumKey: String? = null
@@ -611,11 +647,13 @@
public var artistId: Int? = null
@JvmField
- @Deprecated("This constant was deprecated in API level 30. These keys are generated using" +
+ @Deprecated(
+ "This constant was deprecated in API level 30. These keys are generated using" +
" Locale.ROOT, which means they don't reflect locale-specific sorting preferences" +
". To apply locale-specific sorting preferences, use " +
"ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE.")
+ "ContentResolver#QUERY_ARG_SORT_LOCALE."
+ )
@RequiresApi(30)
@ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ARTIST_KEY)
public var artistKey: String? = null
@@ -648,11 +686,13 @@
public var _id: Int? = null
@JvmField
- @Deprecated("This constant was deprecated in API level 30. These keys are generated using" +
+ @Deprecated(
+ "This constant was deprecated in API level 30. These keys are generated using" +
" Locale.ROOT, which means they don't reflect locale-specific sorting preferences" +
". To apply locale-specific sorting preferences, use " +
"ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE.")
+ "ContentResolver#QUERY_ARG_SORT_LOCALE."
+ )
@ContentColumn(android.provider.MediaStore.Audio.ArtistColumns.ARTIST_KEY)
public var artistKey: String? = null
@@ -693,10 +733,12 @@
public var _id: Int? = null
@JvmField
- @Deprecated("This constant was deprecated in API level 29. Apps may not have filesystem " +
+ @Deprecated(
+ "This constant was deprecated in API level 29. Apps may not have filesystem " +
"permissions to directly access this path. Instead of trying to open this path " +
"directly, apps should use ContentResolver#openFileDescriptor(Uri, String) to " +
- "gain access.")
+ "gain access."
+ )
@ContentColumn(android.provider.MediaStore.Audio.PlaylistsColumns.DATA)
public var data: String? = null
diff --git a/contentaccess/contentaccess-runtime/src/main/kotlin/androidx/contentaccess/runtime/ContentAccess.kt b/contentaccess/contentaccess-runtime/src/main/kotlin/androidx/contentaccess/runtime/ContentAccess.kt
index c418bc2..3646d7b 100644
--- a/contentaccess/contentaccess-runtime/src/main/kotlin/androidx/contentaccess/runtime/ContentAccess.kt
+++ b/contentaccess/contentaccess-runtime/src/main/kotlin/androidx/contentaccess/runtime/ContentAccess.kt
@@ -41,16 +41,23 @@
ContentResolver::class.java,
CoroutineDispatcher::class.java
)
- return constructor.newInstance(contentResolver, queryExecutor
- .asCoroutineDispatcher()) as T
+ return constructor.newInstance(
+ contentResolver,
+ queryExecutor
+ .asCoroutineDispatcher()
+ ) as T
} catch (e: ClassNotFoundException) {
- error("Cannot find generated class for content accessor ${contentAccessObject
- .qualifiedName}, this is most likely because the class is not annotated " +
+ error(
+ "Cannot find generated class for content accessor ${contentAccessObject
+ .qualifiedName}, this is most likely because the class is not annotated " +
"with @ContentAccessObject or because the contentaccess-compiler " +
- "annotation processor was not ran properly.")
+ "annotation processor was not ran properly."
+ )
} catch (e: InstantiationException) {
- error("Unable to instantiate implementation $packageName.$generatedClassName of " +
- "${contentAccessObject.qualifiedName}.")
+ error(
+ "Unable to instantiate implementation $packageName.$generatedClassName of " +
+ "${contentAccessObject.qualifiedName}."
+ )
}
}
}
diff --git a/core/core/src/androidTest/java/androidx/core/os/LocaleListCompatTest.java b/core/core/src/androidTest/java/androidx/core/os/LocaleListCompatTest.java
index f071c00..3fd5f6d 100644
--- a/core/core/src/androidTest/java/androidx/core/os/LocaleListCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/os/LocaleListCompatTest.java
@@ -114,18 +114,6 @@
}
@Test
- public void testRepeatedArguments() {
- final Locale[] la = {Locale.US, Locale.US};
- try {
- LocaleListCompat.create(la);
- fail("Initializing a LocaleListCompat with an array containing duplicates should "
- + "throw.");
- } catch (Throwable e) {
- assertEquals(IllegalArgumentException.class, e.getClass());
- }
- }
-
- @Test
public void testIndexOf() {
final LocaleListCompat empty = LocaleListCompat.create();
assertEquals(-1, empty.indexOf(Locale.US));
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 4e7411f..db9306a 100644
--- a/core/core/src/main/java/androidx/core/os/LocaleListCompatWrapper.java
+++ b/core/core/src/main/java/androidx/core/os/LocaleListCompatWrapper.java
@@ -23,9 +23,11 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
+import java.util.List;
import java.util.Locale;
final class LocaleListCompatWrapper implements LocaleListInterface {
@@ -122,7 +124,7 @@
mList = sEmptyList;
mStringRepresentation = "";
} else {
- final Locale[] localeList = new Locale[list.length];
+ final List<Locale> localeList = new ArrayList<>();
final HashSet<Locale> seenLocales = new HashSet<Locale>();
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.length; i++) {
@@ -130,10 +132,10 @@
if (l == null) {
throw new NullPointerException("list[" + i + "] is null");
} else if (seenLocales.contains(l)) {
- throw new IllegalArgumentException("list[" + i + "] is a repetition");
+ // Ignore repeated locale
} else {
final Locale localeClone = (Locale) l.clone();
- localeList[i] = localeClone;
+ localeList.add(localeClone);
toLanguageTag(sb, localeClone);
if (i < list.length - 1) {
sb.append(',');
@@ -141,7 +143,7 @@
seenLocales.add(localeClone);
}
}
- mList = localeList;
+ mList = localeList.toArray(new Locale[localeList.size()]);
mStringRepresentation = sb.toString();
}
}
diff --git a/customview/customview/build.gradle b/customview/customview/build.gradle
index 474e25e..4ec89b0 100644
--- a/customview/customview/build.gradle
+++ b/customview/customview/build.gradle
@@ -1,11 +1,11 @@
import static androidx.build.dependencies.DependenciesKt.*
import androidx.build.LibraryGroups
-import androidx.build.LibraryVersions
import androidx.build.Publish
plugins {
id("AndroidXPlugin")
id("com.android.library")
+ id("kotlin-android")
}
android {
@@ -20,6 +20,7 @@
api("androidx.core:core:1.3.0-beta01")
implementation("androidx.collection:collection:1.1.0")
+ androidTestImplementation(KOTLIN_STDLIB)
androidTestImplementation(JUNIT)
androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/customview/customview/src/androidTest/AndroidManifest.xml b/customview/customview/src/androidTest/AndroidManifest.xml
index 97b7919..4e5bad6 100644
--- a/customview/customview/src/androidTest/AndroidManifest.xml
+++ b/customview/customview/src/androidTest/AndroidManifest.xml
@@ -18,7 +18,8 @@
package="androidx.customview.test">
<application android:supportsRtl="true">
- <activity android:name="androidx.customview.widget.ExploreByTouchHelperTestActivity"/>
+ <activity android:name="androidx.customview.widget.ExploreByTouchHelperTestActivity" />
+ <activity android:name="androidx.customview.widget.TestActivity" />
</application>
</manifest>
diff --git a/customview/customview/src/androidTest/java/androidx/customview/widget/TestActivity.kt b/customview/customview/src/androidTest/java/androidx/customview/widget/TestActivity.kt
new file mode 100644
index 0000000..65fd739
--- /dev/null
+++ b/customview/customview/src/androidTest/java/androidx/customview/widget/TestActivity.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 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 androidx.customview.widget
+
+import android.app.Activity
+import android.os.Bundle
+
+import androidx.customview.test.R
+
+class TestActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.text_view_activity)
+ }
+}
diff --git a/customview/customview/src/androidTest/java/androidx/customview/widget/ViewDragHelperTest.kt b/customview/customview/src/androidTest/java/androidx/customview/widget/ViewDragHelperTest.kt
new file mode 100644
index 0000000..abc2e38
--- /dev/null
+++ b/customview/customview/src/androidTest/java/androidx/customview/widget/ViewDragHelperTest.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 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 androidx.customview.widget
+
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ViewDragHelperTest {
+ @Suppress("DEPRECATION")
+ @get:Rule
+ val activityRule = androidx.test.rule.ActivityTestRule(TestActivity::class.java)
+
+ @Test
+ fun testProcessTouchEventWithInconsistentStream() {
+ val callback = object : ViewDragHelper.Callback() {
+ override fun tryCaptureView(child: View, pointerId: Int): Boolean = false
+ }
+ activityRule.runOnUiThread {
+ val activity = activityRule.activity
+ val content = activity.findViewById<View>(android.R.id.content)!! as ViewGroup
+ val helper = ViewDragHelper.create(content, callback)
+
+ // Ensure the state is STATE_DRAGGING with the pointer DOWN.
+ helper.processTouchEvent(obtainMotionEvent(MotionEvent.ACTION_DOWN, 2))
+
+ // Set the active pointer ID to match.
+ helper.captureChildView(content.getChildAt(0), 2)
+
+ // Feed in touch event without the pointer ID.
+ helper.processTouchEvent(obtainMotionEvent(MotionEvent.ACTION_MOVE, 0))
+ }
+ }
+}
+
+fun obtainMotionEvent(action: Int, pointerId: Int): MotionEvent {
+ @Suppress("DEPRECATION")
+ return MotionEvent.obtain(
+ System.currentTimeMillis(),
+ System.currentTimeMillis(),
+ action,
+ 1,
+ intArrayOf(pointerId),
+ arrayOf(MotionEvent.PointerCoords()),
+ 0,
+ 0f,
+ 0f,
+ 0,
+ 0,
+ 0,
+ 0
+ )
+}
diff --git a/customview/customview/src/androidTest/res/layout/text_view_activity.xml b/customview/customview/src/androidTest/res/layout/text_view_activity.xml
new file mode 100644
index 0000000..ba5d688
--- /dev/null
+++ b/customview/customview/src/androidTest/res/layout/text_view_activity.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <TextView
+ android:id="@+id/text_view"
+ android:layout_width="200dip"
+ android:layout_height="60dip" />
+</FrameLayout>
diff --git a/customview/customview/src/main/java/androidx/customview/widget/ViewDragHelper.java b/customview/customview/src/main/java/androidx/customview/widget/ViewDragHelper.java
index e6a32cc..9916886 100644
--- a/customview/customview/src/main/java/androidx/customview/widget/ViewDragHelper.java
+++ b/customview/customview/src/main/java/androidx/customview/widget/ViewDragHelper.java
@@ -1191,7 +1191,15 @@
// If pointer is invalid then skip the ACTION_MOVE.
if (!isValidPointerForActionMove(mActivePointerId)) break;
+ // If pointer index is not found then skip.
final int index = ev.findPointerIndex(mActivePointerId);
+ if (index == -1) {
+ Log.w(TAG, "Failed to find pointer index for active pointer ID "
+ + mActivePointerId + ", which may indicate an inconsistent "
+ + "MotionEvent stream");
+ break;
+ }
+
final float x = ev.getX(index);
final float y = ev.getY(index);
final int idx = (int) (x - mLastMotionX[mActivePointerId]);
diff --git a/development/build_log_processor.sh b/development/build_log_processor.sh
index e4ddd19..17462d2 100755
--- a/development/build_log_processor.sh
+++ b/development/build_log_processor.sh
@@ -24,7 +24,7 @@
echo "-Pandroidx.summarizeStderr"
echo " Run build_log_simplifier.py on failure to produce a summary of the build output"
echo
- echo "-Pandroidx.validateNoExtraMessages"
+ echo "-Pandroidx.validateNoUnrecognizedMessages"
echo " Run build_log_simplifier.py --validate on success to confirm that the build generated no unrecognized messages"
exit 1
}
@@ -37,9 +37,9 @@
if [[ " ${@} " =~ " -Pandroidx.summarizeStderr " ]]; then
summarizeOnFailure=true
fi
-validateNoExtraMessagesOnSuccess=false
-if [[ " ${@} " =~ " -Pandroidx.validateNoExtraMessages " ]]; then
- validateNoExtraMessagesOnSuccess=true
+validateNoUnrecognizedMessagesOnSuccess=false
+if [[ " ${@} " =~ " -Pandroidx.validateNoUnrecognizedMessages " ]]; then
+ validateNoUnrecognizedMessagesOnSuccess=true
fi
# run Gradle and save stdout and stderr into $logFile
@@ -66,14 +66,14 @@
shift
echo Running "$programName" "$@"
if "$programName" "$@" > >(tee -a "$logFile") 2>&1; then
- echo "Succeeded: $*" >&2
- if [ "$validateNoExtraMessagesOnSuccess" == "true" ]; then
+ echo "Succeeded: $programName $*" >&2
+ if [ "$validateNoUnrecognizedMessagesOnSuccess" == "true" ]; then
echo "##########################################################################" >&2
$SCRIPT_PATH/build_log_simplifier.py --validate $logFile >&2
fi
else
echo >&2
- echo "Failed: $*" >&2
+ echo "Failed: $programName $*" >&2
echo "############################################################################" >&2
echo "Attempting to locate the relevant error messages via build_log_simplifier.py" >&2
echo "############################################################################" >&2
diff --git a/development/build_log_simplifier/build_log_simplifier.py b/development/build_log_simplifier/build_log_simplifier.py
index 51d7b75..fb24371 100755
--- a/development/build_log_simplifier/build_log_simplifier.py
+++ b/development/build_log_simplifier/build_log_simplifier.py
@@ -199,6 +199,10 @@
# skip comments
continue
regexes.append(line)
+ if remove_control_characters(line) != line:
+ raise Exception("Unexpected control characters found in configuration line:\n\n " +
+ "'" + line + "'\n\n. This line is unexpected to match anything. Is this a copying mistake?")
+
return regexes_matcher(sorted(regexes))
# Returns a regexes_matcher that matches the content of our config file
@@ -286,6 +290,22 @@
result.append(line)
return result
+# Removes color characters and other ANSI control characters from this input
+control_character_regex = re.compile(r"""
+ \x1B # Escape
+ (?: # 7-bit C1 Fe (except CSI)
+ [@-Z\\-_]
+ | # or [ for CSI, followed by a control sequence
+ \[
+ [0-?]* # Parameters
+ [ -/]* # Intermediate bytes
+ [@-~] # End
+ )
+ """, re.VERBOSE)
+
+def remove_control_characters(line):
+ return control_character_regex.sub("", line)
+
# Normalizes some filepaths to more easily simplify/skip some messages
def normalize_paths(lines):
# get OUT_DIR, DIST_DIR, and the path of the root of the checkout
@@ -434,6 +454,7 @@
# read file
log_path = arguments.log_path[0]
lines = readlines(log_path)
+ lines = [remove_control_characters(line) for line in lines]
lines = normalize_paths(lines)
# load configuration
exemption_regexes_from_file = readlines(get_exemptions_path())
@@ -470,7 +491,7 @@
elif arguments.update:
if len(lines) != 0:
update_path = get_exemptions_path()
- suggested = generate_suggested_exemptions(lines, configuration_lines)
+ suggested = generate_suggested_exemptions(lines, exemption_regexes_from_file)
writelines(update_path, suggested)
print("build_log_simplifier.py updated exemptions " + update_path)
else:
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index a4be74b2..c7017e9 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -1,11 +1,1147 @@
# This file is a list of regexes of messages that are permitted to appear in stdout/stderr
# Comments and blank lines are ignored
# Before adding a suppression to this file, please attempt to suppress the output inside the generating tool instead
-
# > Task :docs-runner:dokkaJavaPublicDocs
(logging: loading modules: \[java\.se.*)|(.*No file found when processing Java @sample.*)
# > Task :contentaccess:integration-tests:testapp:kaptDebugAndroidTestKotlin
\[WARN\] Issue detected with androidx\.contentaccess\.compiler\.ContentAccessProcessor\. Expected 1 originating source file when generating [^ ]*, but detected [0-9][0-9]*: \[\]\.
# > Task :icing:extractIncludeDebugAndroidTestProto
proto file '[^ ]*' directly specified in configuration\. It's likely you specified files\('path/to/foo\.proto'\) or fileTree\('path/to/directory'\) in protobuf or compile configuration\. This makes you vulnerable to https://github\.com/google/protobuf\-gradle\-plugin/issues/[0-9][0-9]*\. Please use files\('path/to/directory'\) instead\.
-
+OUT_DIR=\$OUT_DIR
+DIST_DIR=\$DIST_DIR
+CHECKOUT=\$CHECKOUT
+Downloading file:\$SUPPORT/gradle/wrapper/\.\./\.\./\.\./\.\./tools/external/gradle/gradle\-[0-9]+\.[0-9]+\.[0-9]+\-bin\.zip
+\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%
+Welcome to Gradle [0-9]+\.[0-9]+\.[0-9]+!
+Here are the highlights of this release:
+\- Experimental file\-system watching
+\- Improved version ordering
+\- New samples
+For more details see https://docs\.gradle\.org/[0-9]+\.[0-9]+\.[0-9]+/release\-notes\.html
+To honour the JVM settings for this build a new JVM will be forked\. Please consider using the daemon: https://docs\.gradle\.org/[0-9]+\.[0-9]+\.[0-9]+/userguide/gradle_daemon\.html\.
+Daemon will be stopped at the end of the build stopping after processing
+# > Task :buildSrc:build
+> Configure project :appsearch:appsearch\-local\-backend
+WARNING: NDK was located by using ndk\.dir property\. This method is deprecated and will be removed in a future release\. Please use android\.ndkVersion or android\.ndkPath in build\.gradle to specify the NDK to use\. https://developer\.android\.com/r/studio\-ui/ndk\-dir
+NDK was located by using ndk\.dir property\. This method is deprecated and will be removed in a future release\. Please use android\.ndkVersion or android\.ndkPath in build\.gradle to specify the NDK to use\. https://developer\.android\.com/r/studio\-ui/ndk\-dir
+Configuration on demand is an incubating feature\.
+> Configure project :
+updated local\.properties
+> Configure project :compose:test\-utils
+Kotlin Multiplatform Projects are an Alpha feature\.
+The following Kotlin source sets were configured but not added to any Kotlin compilation:
+\* androidAndroidTestRelease
+\* androidTestRelease
+\* test
+You can add a source set to a target's compilation by connecting it with the compilation's default source set using 'dependsOn'\.
+See https://kotlinlang\.org/docs/reference/building\-mpp\-with\-gradle\.html\#connecting\-source\-sets
+The Kotlin source set test was configured but not added to any Kotlin compilation\. You can add a source set to a target's compilation by connecting it with the compilation's default source set using 'dependsOn'\.
+\* jvmMain
+# > Task :listTaskOutputs
+Wrote \$DIST_DIR/task_outputs\.txt
+See https://docs\.gradle\.org/[0-9]+\.[0-9]+\.[0-9]+/userguide/command_line_interface\.html\#sec:command_line_warnings
+BUILD SUCCESSFUL in [0-9]+m [0-9]+s
+[0-9]+ actionable task: [0-9]+ executed
+# > Task :docs-fake:processPublicReleaseMainManifest
+\$SUPPORT/docs\-fake/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+application@android:appComponentFactory was tagged at AndroidManifest\.xml:[0-9]+ to replace other declarations but no other declaration present
+# > Task :doclava:compileJava
+Note: Some input files use or override a deprecated API that is marked for removal\.
+Note: Recompile with \-Xlint:removal for details\.
+# > Task :test-screenshot:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/test\-screenshot_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :benchmark:benchmark-junit4:processDebugAndroidTestManifest
+\$SUPPORT/benchmark/junit[0-9]+/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.benchmark\.junit[0-9]+\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :benchmark:benchmark-common:processDebugAndroidTestManifest
+\$SUPPORT/benchmark/common/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :tracing:tracing:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/tracing/tracing/src/androidTest/java/androidx/tracing/TraceTest\.java uses or overrides a deprecated API\.
+# > Task :tracing:tracing-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/tracing\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :ui:ui-tooling:processDebugAndroidTestManifest
+\$SUPPORT/ui/ui\-tooling/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.ui\.tooling\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/ui/ui/ui\-tooling/build/intermediates/tmp/manifest/androidTest/debug/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+application@android:debuggable was tagged at manifestMerger[0-9]+\.xml:[0-9]+ to replace other declarations but no other declaration present
+# > Task :generateSdkApi
+javadoc: warning \- The old Doclet and Taglet APIs in the packages
+com\.sun\.javadoc, com\.sun\.tools\.doclets and their implementations
+are planned to be removed in a future JDK release\. These
+components have been superseded by the new APIs in jdk\.javadoc\.doclet\.
+Users are strongly recommended to migrate to the new APIs\.
+# > Task :compose:foundation:foundation-layout:processDebugAndroidTestManifest
+\$OUT_DIR/ui/compose/foundation/foundation\-layout/build/intermediates/tmp/manifest/androidTest/debug/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :benchmark:benchmark-junit4:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/benchmark\-junit[0-9]+_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :benchmark:benchmark-common:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/benchmark\-common_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:integration-tests:benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/compose/integration\-tests/benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.ui\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/ui/compose/integration\-tests/benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :compose:ui:ui-geometry:compileKotlinMetadata
+w: \$SUPPORT/compose/ui/ui\-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Radius\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+# > Task :compose:navigation:navigation:processDebugAndroidTestManifest
+\$SUPPORT/compose/navigation/navigation/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.compose\.navigation\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :compose:runtime:runtime-saved-instance-state:processDebugAndroidTestManifest
+\$OUT_DIR/ui/compose/runtime/runtime\-saved\-instance\-state/build/intermediates/tmp/manifest/androidTest/debug/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :compose:runtime:runtime-dispatch:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/runtime\-dispatch_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:ui:ui-graphics:compileKotlinMetadata
+w: \$SUPPORT/compose/ui/ui\-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Color\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+w: \$SUPPORT/compose/ui/ui\-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Float[0-9]+\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+# > Task :distpublicDocs
+'Wrote API reference to \$DIST_DIR/androidx\-public\-docs\-[0-9]+\.zip
+# > Task :compose:runtime:runtime:benchmark:processReleaseAndroidTestManifest
+\$OUT_DIR/ui/compose/runtime/runtime/benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :compose:material:material-icons-extended:processDebugAndroidTestManifest
+\[:compose:material:material\-icons\-extended\] \$OUT_DIR/ui/compose/material/material\-icons\-extended/build/intermediates/library_manifest/debug/AndroidManifest\.xml Warning:
+Package name 'androidx\.compose\.material\.icons' used in: :compose:material:material\-icons\-extended, :compose:material:material\-icons\-core\.
+# > Task :compose:ui:ui-text-android:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-text\-android_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:ui:ui:compileKotlinMetadata
+w: Runtime JAR files in the classpath should have the same version\. These files were found in the classpath:
+\$CHECKOUT/prebuilts/androidx/external/org/jetbrains/kotlin/kotlin\-stdlib/[0-9]+\.[0-9]+\.[0-9]+/kotlin\-stdlib\-[0-9]+\.[0-9]+\.[0-9]+\.jar \(version [0-9]+\.[0-9]+\)
+\$CHECKOUT/prebuilts/androidx/external/org/jetbrains/kotlin/kotlin\-stdlib\-common/[0-9]+\.[0-9]+\.[0-9]+/kotlin\-stdlib\-common\-[0-9]+\.[0-9]+\.[0-9]+\.jar \(version [0-9]+\.[0-9]+\)
+w: Some runtime JAR files in the classpath have an incompatible version\. Consider removing them from the classpath
+w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/DrawLayerModifier\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorAssetBuilder\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/Key\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Measured\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DepthSortedSet\.kt: \([0-9]+, [0-9]+\): The corresponding parameter in the supertype 'Comparator' is named 'a'\. This may cause problems when calling this function with named arguments\.
+w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DepthSortedSet\.kt: \([0-9]+, [0-9]+\): The corresponding parameter in the supertype 'Comparator' is named 'b'\. This may cause problems when calling this function with named arguments\.
+# > Task :compose:animation:animation:compileKotlinMetadata
+w: \$SUPPORT/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys\.kt: \([0-9]+, [0-9]+\): 'PxBounds' is deprecated\. Use Rect instead
+w: \$SUPPORT/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation\.kt: \([0-9]+, [0-9]+\): 'PxBounds' is deprecated\. Use Rect instead
+# > Task :compose:foundation:foundation:compileKotlinMetadata
+w: \$SUPPORT/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyForState\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+# > Task :benchmark:benchmark-common:runErrorProne
+\$SUPPORT/benchmark/common/src/main/java/androidx/benchmark/simpleperf/RecordOptions\.java:[0-9]+: warning: \[JavaTimeDefaultTimeZone\] LocalDateTime\.now\(\) is not allowed because it silently uses the system default time\-zone\. You must pass an explicit time\-zone \(e\.g\., ZoneId\.of\("America/Los_Angeles"\)\) to this method\.
+LocalDateTime time = LocalDateTime\.now\(\);
+\^
+\(see https://errorprone\.info/bugpattern/JavaTimeDefaultTimeZone\)
+Did you mean 'LocalDateTime time = LocalDateTime\.now\(ZoneId\.systemDefault\(\)\);'\?
+[0-9]+ warning
+# > Task :compose:runtime:runtime:generateApi
+src/commonMain/kotlin/androidx/compose/runtime/Composer\.kt:[0-9]+: warning: Field ComposerKt\.ambientMap references hidden type androidx\.compose\.runtime\.OpaqueKey\. \[HiddenTypeParameter\]
+src/commonMain/kotlin/androidx/compose/runtime/Composer\.kt:[0-9]+: warning: Field ComposerKt\.invocation references hidden type androidx\.compose\.runtime\.OpaqueKey\. \[HiddenTypeParameter\]
+src/commonMain/kotlin/androidx/compose/runtime/Composer\.kt:[0-9]+: warning: Field ComposerKt\.provider references hidden type androidx\.compose\.runtime\.OpaqueKey\. \[HiddenTypeParameter\]
+src/commonMain/kotlin/androidx/compose/runtime/Composer\.kt:[0-9]+: warning: Field ComposerKt\.providerMaps references hidden type androidx\.compose\.runtime\.OpaqueKey\. \[HiddenTypeParameter\]
+src/commonMain/kotlin/androidx/compose/runtime/Composer\.kt:[0-9]+: warning: Field ComposerKt\.providerValues references hidden type androidx\.compose\.runtime\.OpaqueKey\. \[HiddenTypeParameter\]
+src/commonMain/kotlin/androidx/compose/runtime/Composer\.kt:[0-9]+: warning: Field ComposerKt\.reference references hidden type androidx\.compose\.runtime\.OpaqueKey\. \[HiddenTypeParameter\]
+# > Task :compose:ui:ui-geometry:generateApi
+src/commonMain/kotlin/androidx/compose/ui/geometry/MutableRect\.kt:[0-9]+: info: Note that adding the `operator` keyword would allow calling this method using operator syntax \[KotlinOperator\]
+# > Task :compose:animation:animation-core:generateApi
+src/commonMain/kotlin/androidx/compose/animation/core/AnimationClock\.kt:[0-9]+: warning: Field BaseAnimationClock\.Companion references hidden type androidx\.compose\.animation\.core\.BaseAnimationClock\.Companion\. \[HiddenTypeParameter\]
+# > Task :compose:ui:ui-unit:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-unit_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:foundation:foundation-layout:generateApi
+src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl\.kt:[0-9]+: warning: Parameter orientation references hidden type androidx\.compose\.foundation\.layout\.LayoutOrientation\. \[HiddenTypeParameter\]
+src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl\.kt:[0-9]+: warning: Parameter crossAxisAlignment references hidden type androidx\.compose\.foundation\.layout\.CrossAxisAlignment\. \[HiddenTypeParameter\]
+# > Task :compose:animation:animation:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/animation_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:runtime:runtime-livedata:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/runtime\-livedata_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:foundation:foundation-text:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/foundation\-text_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:runtime:runtime:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/runtime_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:navigation:navigation:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:foundation:foundation:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/foundation_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:runtime:runtime-rxjava2:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/runtime\-rxjava[0-9]+_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:runtime:runtime-saved-instance-state:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/runtime\-saved\-instance\-state_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:ui:ui-graphics:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-graphics_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:ui:ui-text:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-text_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:ui:ui-viewbinding:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-viewbinding_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:foundation:foundation-layout:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/foundation\-layout_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:test-utils:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/test\-utils_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:integration-tests:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/integration\-tests_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :ui:ui-test:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-test_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :ui:ui-tooling:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-tooling_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:ui:ui:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:material:material:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/material_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :disttipOfTreeDocs
+'Wrote API reference to \$DIST_DIR/androidx\-tipOfTree\-docs\-[0-9]+\.zip
+# > Task :compose:material:material-icons-extended:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/material\-icons\-extended_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :buildOnServer
+[0-9]+ actionable tasks: [0-9]+ executed, [0-9]+ up\-to\-date
+[0-9]+ actionable tasks: [0-9]+ executed, [0-9]+ from cache, [0-9]+ up\-to\-date
+[0-9]+ actionable tasks: [0-9]+ executed, [0-9]+ from cache
+# > Task :lifecycle:lifecycle-common:compileJava
+Note: \$SUPPORT/lifecycle/lifecycle\-common/src/main/java/androidx/lifecycle/Lifecycling\.java uses or overrides a deprecated API\.
+# > Task :concurrent:concurrent-futures:compileJava
+Note: \$SUPPORT/concurrent/futures/src/main/java/androidx/concurrent/futures/CallbackToFutureAdapter\.java uses or overrides a deprecated API\.
+# > Task :contentpager:contentpager:compileReleaseJavaWithJavac
+Note: \$SUPPORT/contentpager/contentpager/src/main/java/androidx/contentpager/content/LoaderQueryRunner\.java uses or overrides a deprecated API\.
+# > Task :coordinatorlayout:coordinatorlayout:compileReleaseJavaWithJavac
+Note: \$SUPPORT/coordinatorlayout/coordinatorlayout/src/main/java/androidx/coordinatorlayout/widget/CoordinatorLayout\.java uses or overrides a deprecated API\.
+# > Task :customview:customview:compileReleaseJavaWithJavac
+Note: \$SUPPORT/customview/customview/src/main/java/androidx/customview/widget/ExploreByTouchHelper\.java uses or overrides a deprecated API\.
+# > Task :recommendation:recommendation:compileReleaseJavaWithJavac
+Note: \$SUPPORT/recommendation/recommendation/src/main/java/androidx/recommendation/app/ContentRecommendation\.java uses or overrides a deprecated API\.
+# > Task :textclassifier:textclassifier:compileReleaseJavaWithJavac
+Note: \$SUPPORT/textclassifier/textclassifier/src/main/java/androidx/textclassifier/TextClassifier\.java uses or overrides a deprecated API\.
+# > Task :publicDocsTask
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ByteArrayFrame\.java:[0-9]+: error: cannot find symbol
+import androidx\.media[0-9]+\.exoplayer\.external\.Format;
+symbol: class Format
+location: package androidx\.media[0-9]+\.exoplayer\.external
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ByteArrayFrame\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.metadata does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.metadata\.Metadata;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ByteArrayFrame\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.util does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.util\.Util;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ByteArrayFrame\.java:[0-9]+: error: package Metadata does not exist
+/\* package \*/ final class ByteArrayFrame implements Metadata\.Entry \{
+public static final Creator<ByteArrayFrame> CREATOR =
+symbol: class Creator
+location: class ByteArrayFrame
+public Format getWrappedMetadataFormat\(\) \{
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/DataSourceCallbackDataSource\.java:[0-9]+: error: cannot find symbol
+import androidx\.media[0-9]+\.exoplayer\.external\.C;
+symbol: class C
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/DataSourceCallbackDataSource\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.upstream does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.upstream\.BaseDataSource;
+import androidx\.media[0-9]+\.exoplayer\.external\.upstream\.DataSource;
+import androidx\.media[0-9]+\.exoplayer\.external\.upstream\.DataSpec;
+/\* package \*/ final class DataSourceCallbackDataSource extends BaseDataSource \{
+symbol: class BaseDataSource
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/DataSourceCallbackDataSource\.java:[0-9]+: error: package DataSource does not exist
+static DataSource\.Factory getFactory\(
+public long open\(DataSpec dataSpec\) throws IOException \{
+symbol: class DataSpec
+location: class DataSourceCallbackDataSource
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerMediaPlayer[0-9]+Impl\.java:[0-9]+: error: cannot find symbol
+import androidx\.media[0-9]+\.exoplayer\.external\.Player;
+symbol: class Player
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: cannot find symbol
+import androidx\.media[0-9]+\.exoplayer\.external\.ExoPlaybackException;
+symbol: class ExoPlaybackException
+import androidx\.media[0-9]+\.exoplayer\.external\.SimpleExoPlayer;
+symbol: class SimpleExoPlayer
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.audio does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AudioAttributes;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AudioCapabilities;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AudioListener;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AudioProcessor;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AuxEffectInfo;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.DefaultAudioSink;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.decoder does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.decoder\.DecoderCounters;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.metadata does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.metadata\.MetadataOutput;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.source does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.source\.ClippingMediaSource;
+import androidx\.media[0-9]+\.exoplayer\.external\.source\.ConcatenatingMediaSource;
+import androidx\.media[0-9]+\.exoplayer\.external\.source\.MediaSource;
+import androidx\.media[0-9]+\.exoplayer\.external\.source\.TrackGroup;
+import androidx\.media[0-9]+\.exoplayer\.external\.source\.TrackGroupArray;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.trackselection does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.trackselection\.TrackSelectionArray;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.upstream does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.upstream\.DefaultBandwidthMeter;
+import androidx\.media[0-9]+\.exoplayer\.external\.upstream\.DefaultDataSourceFactory;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.util does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.util\.MimeTypes;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.video does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.video\.VideoRendererEventListener;
+private final DefaultBandwidthMeter mBandwidthMeter;
+symbol: class DefaultBandwidthMeter
+location: class ExoPlayerWrapper
+private SimpleExoPlayer mPlayer;
+private DefaultAudioSink mAudioSink;
+symbol: class DefaultAudioSink
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: cannot find symbol
+import androidx\.media[0-9]+\.exoplayer\.external\.Renderer;
+symbol: class Renderer
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.audio does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AudioRendererEventListener;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AudioSink;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.MediaCodecAudioRenderer;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.drm does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.drm\.DrmSessionManager;
+import androidx\.media[0-9]+\.exoplayer\.external\.drm\.FrameworkMediaCrypto;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.mediacodec does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.mediacodec\.MediaCodecSelector;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.metadata does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.metadata\.MetadataRenderer;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.text does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.text\.TextOutput;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.video does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.video\.MediaCodecVideoRenderer;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TextRenderer\.java:[0-9]+: error: cannot find symbol
+import androidx\.media[0-9]+\.exoplayer\.external\.BaseRenderer;
+symbol: class BaseRenderer
+import androidx\.media[0-9]+\.exoplayer\.external\.FormatHolder;
+symbol: class FormatHolder
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TextRenderer\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.text does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.text\.SubtitleInputBuffer;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TextRenderer\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.util does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.util\.ParsableByteArray;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TrackSelector\.java:[0-9]+: error: cannot find symbol
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TrackSelector\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.source does not exist
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TrackSelector\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.trackselection does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.trackselection\.DefaultTrackSelector;
+import androidx\.media[0-9]+\.exoplayer\.external\.trackselection\.MappingTrackSelector;
+import androidx\.media[0-9]+\.exoplayer\.external\.trackselection\.TrackSelection;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TrackSelector\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.util does not exist
+implements androidx\.media[0-9]+\.exoplayer\.external\.RenderersFactory \{
+symbol: class RenderersFactory
+/\* package \*/ class TextRenderer extends BaseRenderer \{
+symbol: class BaseRenderer
+void handlePlayerTracksChanged\(TrackSelectionArray trackSelections\) \{
+symbol: class TrackSelectionArray
+void handlePlayerError\(ExoPlaybackException exception\) \{
+void handleMetadata\(Metadata metadata\) \{
+symbol: class Metadata
+final DefaultAudioSink audioSink,
+private final SimpleExoPlayer mPlayer;
+location: class MediaItemQueue
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package DataSource does not exist
+private final DataSource\.Factory mDataSourceFactory;
+private final ConcatenatingMediaSource mConcatenatingMediaSource;
+symbol: class ConcatenatingMediaSource
+MediaItemQueue\(Context context, SimpleExoPlayer player, Listener listener\) \{
+Collection<MediaSource> mediaSources\) \{
+symbol: class MediaSource
+private final DefaultTrackSelector mDefaultTrackSelector;
+symbol: class DefaultTrackSelector
+location: class TrackSelector
+public DefaultTrackSelector getPlayerTrackSelector\(\) \{
+public void handlePlayerTracksChanged\(MediaItem item, TrackSelectionArray trackSelections\) \{
+private final AudioSink mAudioSink;
+symbol: class AudioSink
+location: class RenderersFactory
+AudioSink audioSink,
+VideoRendererEventListener videoRendererEventListener,
+symbol: class VideoRendererEventListener
+AudioRendererEventListener audioRendererEventListener,
+symbol: class AudioRendererEventListener
+TextOutput textRendererOutput,
+symbol: class TextOutput
+MetadataOutput metadataRendererOutput,
+symbol: class MetadataOutput
+@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager\) \{
+symbol: class DrmSessionManager
+symbol: class FrameworkMediaCrypto
+public Renderer\[\] createRenderers\(
+private final ParsableByteArray mCcData;
+symbol: class ParsableByteArray
+location: class TextRenderer
+private final FormatHolder mFormatHolder;
+private final SubtitleInputBuffer mInputBuffer;
+symbol: class SubtitleInputBuffer
+private final ParsableByteArray mScratch;
+public int supportsFormat\(Format format\) \{
+[0-9]+ warnings
+# > Task :appsearch:appsearch-local-backend:externalNativeBuildRelease
+ninja: no work to do\.
+Build icing_armeabi\-v[0-9]+a
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/release/armeabi\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/io_win[0-9]+\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/zero_copy_stream\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/statusor\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/bytestream\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/strtod\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/arena\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/gzip_stream\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/time\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/zero_copy_stream_impl\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/status\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/structurally_valid\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/any_lite\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/implicit_weak_message\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/generated_enum_util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/stringprintf\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/service\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/int[0-9]+\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/stringpiece\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/mathlimits\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/any\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/common\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/message_lite\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/empty\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/wire_format_lite\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/any\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/coded_stream\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/substitute\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/error_listener\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/delimited_message_util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object icu\-target/CMakeFiles/libandroidicu\.dir/static_shim/shim\.cpp\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/parse_context\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/field_mask\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/tokenizer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/duration\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/unknown_field_set\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_escaping\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/timestamp\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/printer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/field_comparator\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/api\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/strutil\.cc\.o
+\[[0-9]+/[0-9]+\] Linking CXX static library icu\-target/liblibandroidicu\.a
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/source_context\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/object_writer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/generated_message_util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/compiler/importer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.cc\.o
+In file included from \$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.cc:[0-9]+:
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'StartObject' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* StartObject\(StringPiece name\);
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/object_writer\.h:[0-9]+:[0-9]+: note: overridden virtual function is here
+virtual ObjectWriter\* StartObject\(StringPiece name\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'EndObject' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* EndObject\(\);
+virtual ObjectWriter\* EndObject\(\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'StartList' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* StartList\(StringPiece name\);
+virtual ObjectWriter\* StartList\(StringPiece name\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'EndList' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* EndList\(\);
+virtual ObjectWriter\* EndList\(\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderBool' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderBool\(StringPiece name, bool value\);
+virtual ObjectWriter\* RenderBool\(StringPiece name, bool value\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderInt[0-9]+' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderInt[0-9]+\(StringPiece name, int[0-9]+ value\);
+virtual ObjectWriter\* RenderInt[0-9]+\(StringPiece name, int[0-9]+ value\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderUint[0-9]+' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderUint[0-9]+\(StringPiece name, uint[0-9]+ value\);
+virtual ObjectWriter\* RenderUint[0-9]+\(StringPiece name, uint[0-9]+ value\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderDouble' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderDouble\(StringPiece name, double value\);
+virtual ObjectWriter\* RenderDouble\(StringPiece name, double value\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderFloat' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderFloat\(StringPiece name, float value\);
+virtual ObjectWriter\* RenderFloat\(StringPiece name, float value\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderString' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderString\(StringPiece name,
+virtual ObjectWriter\* RenderString\(StringPiece name,
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderBytes' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderBytes\(StringPiece name, StringPiece value\);
+virtual ObjectWriter\* RenderBytes\(StringPiece name, StringPiece value\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderNull' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderNull\(StringPiece name\);
+virtual ObjectWriter\* RenderNull\(StringPiece name\) = [0-9]+;
+[0-9]+ warnings generated\.
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/reflection_ops\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/extension_set_heavy\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_stream_parser\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/repeated_field\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/dynamic_message\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/field_mask_util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/field_mask_utility\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/type_info_test_helper\.cc\.o
+In file included from \$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/type_info_test_helper\.cc:[0-9]+:
+In file included from \$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/type_info_test_helper\.h:[0-9]+:
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/default_value_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderNull' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual DefaultValueObjectWriter\* RenderNull\(StringPiece name\);
+[0-9]+ warning generated\.
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/time_util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/utility\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/type\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/json_util\.cc\.o
+In file included from \$CHECKOUT/external/protobuf/src/google/protobuf/util/json_util\.cc:[0-9]+:
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/map_field\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/datapiece\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/type_info\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/generated_message_table_driven_lite\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/type_resolver_util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/generated_message_reflection\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/protostream_objectsource\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/extension_set\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/default_value_objectwriter\.cc\.o
+In file included from \$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/default_value_objectwriter\.cc:[0-9]+:
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/struct\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/wrappers\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/message\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/generated_message_table_driven\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/proto_writer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/wire_format\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/compiler/parser\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/protostream_objectwriter\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/descriptor_database\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/text_format\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/message_differencer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/descriptor\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/descriptor\.cc\.o
+\[[0-9]+/[0-9]+\] Linking CXX static library protobuf\-target/libprotobuf\.a
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/reset\.pb\.cc, icing\-protobuf\-gen/icing/proto/reset\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/term\.pb\.cc, icing\-protobuf\-gen/icing/proto/term\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/status\.pb\.cc, icing\-protobuf\-gen/icing/proto/status\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/scoring\.pb\.cc, icing\-protobuf\-gen/icing/proto/scoring\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/initialize\.pb\.cc, icing\-protobuf\-gen/icing/proto/initialize\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/optimize\.pb\.cc, icing\-protobuf\-gen/icing/proto/optimize\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/legacy/index/proto/icing\-dynamic\-trie\-header\.pb\.cc, icing\-protobuf\-gen/icing/legacy/index/proto/icing\-dynamic\-trie\-header\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/persist\.pb\.cc, icing\-protobuf\-gen/icing/proto/persist\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/document_wrapper\.pb\.cc, icing\-protobuf\-gen/icing/proto/document_wrapper\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/document\.pb\.cc, icing\-protobuf\-gen/icing/proto/document\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/search\.pb\.cc, icing\-protobuf\-gen/icing/proto/search\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/schema\.pb\.cc, icing\-protobuf\-gen/icing/proto/schema\.pb\.h
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/absl_ports/canonical_errors\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/core/icing\-timer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/absl_ports/str_cat\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/core/icing\-string\-util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/text_classifier/lib[0-9]+/utils/base/logging\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/file/memory\-mapped\-file\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/term\-id\-codec\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/text_classifier/lib[0-9]+/utils/base/logging_raw\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-mmapper\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/absl_ports/annotate\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-storage\-file\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/text_classifier/lib[0-9]+/utils/java/jni\-base\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/util/clock\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/jni/jni\-cache\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/text_classifier/lib[0-9]+/utils/base/status\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/hit/hit\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/hit/doc\-hit\-info\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/file/file\-backed\-bitmap\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/tokenization/reverse_jni/reverse\-jni\-language\-segmenter\-factory\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-flash\-bitmap\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-array\-storage\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-storage\-collection\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/text_classifier/lib[0-9]+/utils/hash/farmhash\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/transform/map/map\-normalizer\-factory\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/tokenization/raw\-query\-tokenizer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/text_classifier/lib[0-9]+/utils/java/jni\-helper\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-all\-document\-id\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/file/filesystem\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/main/index\-block\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/util/crc[0-9]+\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/tokenization/plain\-tokenizer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-not\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-lite\-index\-options\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/term\-property\-id\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/tokenization/reverse_jni/reverse\-jni\-language\-segmenter\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-filesystem\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/main/posting\-list\-used\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/transform/map/normalization\-map\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/jni/reverse\-jni\-break\-iterator\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/transform/map/map\-normalizer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-or\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/util/i[0-9]+n\-utils\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/performance\-configuration\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/main/posting\-list\-utils\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-section\-restrict\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/index\-processor\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/tokenization/tokenizer\-factory\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/index\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/scoring/ranker\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/result/result\-state\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-and\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-filter\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-term\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/document_wrapper\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/jni/icing\-search\-engine\-jni\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/scoring/scoring\-processor\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/optimize\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/initialize\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/term\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/persist\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/lite/lite\-index\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/result/result\-retriever\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/legacy/index/proto/icing\-dynamic\-trie\-header\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/scoring/scorer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/reset\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/scoring\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/status\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/result/snippet\-retriever\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/util/document\-validator\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/document\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/schema/schema\-util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/query/query\-processor\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/schema\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/schema/section\-manager\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/result/result\-state\-manager\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/schema/schema\-store\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-dynamic\-trie\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/search\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/icing\-search\-engine\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/store/document\-store\.cc\.o
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/release/obj/armeabi\-v[0-9]+a/libicing\.so
+Build icing_arm[0-9]+\-v[0-9]+a
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/release/arm[0-9]+\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/release/obj/arm[0-9]+\-v[0-9]+a/libicing\.so
+Build icing_x[0-9]+
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/release/x[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/release/obj/x[0-9]+/libicing\.so
+Build icing_x[0-9]+_[0-9]+
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/release/x[0-9]+_[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/release/obj/x[0-9]+_[0-9]+/libicing\.so
+# > Task :support-animation-demos:compileDebugJavaWithJavac
+Note: \$SUPPORT/samples/SupportAnimationDemos/src/main/java/com/example/android/support/animation/SpringView\.java uses or overrides a deprecated API\.
+# > Task :lint-demos:lint-demo-appcompat:compileDebugJavaWithJavac
+Note: \$SUPPORT/lint\-demos/lint\-demo\-appcompat/src/main/java/com/example/android/appcompat/AppCompatLintDemo\.java uses or overrides a deprecated API\.
+# > Task :support-transition-demos:compileDebugJavaWithJavac
+Note: \$SUPPORT/samples/SupportTransitionDemos/src/main/java/com/example/android/support/transition/widget/FragmentTransitionUsage\.java uses or overrides a deprecated API\.
+# > Task :support-content-demos:compileDebugJavaWithJavac
+Note: \$SUPPORT/samples/SupportContentDemos/src/main/java/com/example/android/support/content/demos/ContentPagerDemoActivity\.java uses or overrides a deprecated API\.
+# > Task :support-preference-demos:compileDebugJavaWithJavac
+Note: \$SUPPORT/samples/SupportPreferenceDemos/src/main/java/com/example/androidx/preference/LeanbackPreferences\.java uses or overrides a deprecated API\.
+# > Task :startup:integration-tests:first-library:processDebugManifest
+\$SUPPORT/startup/integration\-tests/first\-library/src/main/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+provider\#androidx\.work\.impl\.WorkManagerInitializer was tagged at AndroidManifest\.xml:[0-9]+ to remove other declarations but no other declaration present
+# > Task :camera:integration-tests:camera-testapp-extensions:compileDebugJavaWithJavac
+Note: \$SUPPORT/camera/integration\-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity\.java uses or overrides a deprecated API\.
+# > Task :camera:integration-tests:camera-testapp-core:compileDebugJavaWithJavac
+Note: \$SUPPORT/camera/integration\-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity\.java uses or overrides a deprecated API\.
+# > Task :room:integration-tests:room-testapp:processDebugMainManifest
+\[androidx\.vectordrawable:vectordrawable\-animated:[0-9]+\.[0-9]+\.[0-9]+\] \$OUT_DIR/\.gradle/caches/transforms\-[0-9]+/files\-[0-9]+\.[0-9]+/[0-9a-f]{32}/vectordrawable\-animated\-[0-9]+\.[0-9]+\.[0-9]+/AndroidManifest\.xml Warning:
+Package name 'androidx\.vectordrawable' used in: androidx\.vectordrawable:vectordrawable\-animated:[0-9]+\.[0-9]+\.[0-9]+, androidx\.vectordrawable:vectordrawable:[0-9]+\.[0-9]+\.[0-9]+\.
+# > Task :lifecycle:integration-tests:lifecycle-testapp:compileDebugJavaWithJavac
+Note: \$SUPPORT/lifecycle/integration\-tests/testapp/src/main/java/androidx/lifecycle/testapp/FrameworkLifecycleRegistryActivity\.java uses or overrides a deprecated API\.
+# > Task :support-slices-demos:compileDebugJavaWithJavac
+Note: \$SUPPORT/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser\.java uses unchecked or unsafe operations\.
+# > Task :ads-identifier:processDebugAndroidTestManifest
+\$SUPPORT/ads/ads\-identifier/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.ads\.identifier\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :sharetarget:integration-tests:testapp:compileDebugJavaWithJavac
+Note: \$SUPPORT/sharetarget/integration\-tests/testapp/src/main/java/androidx/sharetarget/testapp/MainActivity\.java uses or overrides a deprecated API\.
+# > Task :ads-identifier-provider:processDebugAndroidTestManifest
+\$SUPPORT/ads/ads\-identifier\-provider/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.ads\.identifier\.provider\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :hilt:integration-tests:hilt-testapp-viewmodel:compileDebugJavaWithJavac
+Note: \$OUT_DIR/androidx/hilt/integration\-tests/hilt\-testapp\-viewmodel/build/generated/source/kapt/debug/androidx/hilt/integration/viewmodelapp/Hilt_SimpleFragment\.java uses or overrides a deprecated API\.
+# > Task :ads-identifier-benchmark:processReleaseAndroidTestManifest
+\$OUT_DIR/androidx/ads\-identifier\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :internal-testutils-runtime:processDebugAndroidTestManifest
+\$SUPPORT/testutils/testutils\-runtime/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.testutils\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :slice-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/slices/benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.slice\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/slice\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :internal-testutils-runtime:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/internal\-testutils\-runtime_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :internal-testutils-navigation:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/internal\-testutils\-navigation_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :slice-builders-ktx:processDebugAndroidTestManifest
+\$SUPPORT/slices/builders/ktx/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.slice\.builders\.ktx\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :slice-core:processDebugAndroidTestManifest
+\$SUPPORT/slices/core/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.slice\.core\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :slice-remotecallback:processDebugAndroidTestManifest
+\$SUPPORT/slices/remotecallback/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.slice\.remotecallback\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :slice-view:processDebugAndroidTestManifest
+\$SUPPORT/slices/view/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.slice\.view\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :slice-benchmark:compileReleaseAndroidTestJavaWithJavac
+Note: \$SUPPORT/slices/benchmark/src/androidTest/java/androidx/slice/SliceSerializeMetrics\.java uses or overrides a deprecated API\.
+# > Task :slice-builders-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/slice\-builders\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :support-media-test-client:processDebugAndroidTestManifest
+\$SUPPORT/media/version\-compat\-tests/current/client/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'android\.support\.mediacompat\.client\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :support-media-test-client-previous:processDebugAndroidTestManifest
+\$SUPPORT/media/version\-compat\-tests/previous/client/src/androidTest/AndroidManifest\.xml Warning:
+# > Task :support-media-test-service:processDebugAndroidTestManifest
+\$SUPPORT/media/version\-compat\-tests/current/service/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'android\.support\.mediacompat\.service\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :support-media-test-service-previous:processDebugAndroidTestManifest
+\$SUPPORT/media/version\-compat\-tests/previous/service/src/androidTest/AndroidManifest\.xml Warning:
+# > Task :support-media2-test-client:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/session/version\-compat\-tests/current/client/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.media[0-9]+\.test\.client\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :support-media-test-service:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/media/version\-compat\-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest\.java uses or overrides a deprecated API\.
+# > Task :support-media2-test-client-previous:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/session/version\-compat\-tests/previous/client/src/androidTest/AndroidManifest\.xml Warning:
+# > Task :support-media2-test-service:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/session/version\-compat\-tests/current/service/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.media[0-9]+\.test\.service\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :support-media2-test-service-previous:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/session/version\-compat\-tests/previous/service/src/androidTest/AndroidManifest\.xml Warning:
+# > Task :support-media-test-client:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/media/version\-compat\-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest\.java uses or overrides a deprecated API\.
+# > Task :support-media2-test-service:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/media[0-9]+/session/version\-compat\-tests/current/service/src/androidTest/java/androidx/media[0-9]+/test/service/MockPlayer\.java uses unchecked or unsafe operations\.
+# > Task :support-media2-test-service-previous:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/media[0-9]+/session/version\-compat\-tests/previous/service/src/androidTest/java/androidx/media[0-9]+/test/service/MockPlayer\.java uses unchecked or unsafe operations\.
+# > Task :activity:activity:processDebugAndroidTestManifest
+\$SUPPORT/activity/activity/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.activity\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :appcompat:appcompat:processDebugAndroidTestManifest
+\[:internal\-testutils\-appcompat\] \$OUT_DIR/androidx/internal\-testutils\-appcompat/build/intermediates/library_manifest/debug/AndroidManifest\.xml Warning:
+Package name 'androidx\.testutils' used in: :internal\-testutils\-appcompat, :internal\-testutils\-runtime\.
+# > Task :appcompat:appcompat-resources:processDebugAndroidTestManifest
+\$SUPPORT/appcompat/appcompat\-resources/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.appcompat\.resources\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :appcompat:appcompat-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/appcompat/appcompat\-benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.appcompat\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/appcompat/appcompat\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :activity:activity-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/activity\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :benchmark:benchmark-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/benchmark/benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.benchmark\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/benchmark/benchmark\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :camera:camera-camera2:processDebugAndroidTestManifest
+\$SUPPORT/camera/camera\-camera[0-9]+/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.camera\.camera[0-9]+\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :camera:camera-core:processDebugAndroidTestManifest
+\$SUPPORT/camera/camera\-core/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.camera\.core\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :camera:camera-extensions:processDebugAndroidTestManifest
+\$SUPPORT/camera/camera\-extensions/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.camera\.extensions\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :camera:camera-lifecycle:processDebugAndroidTestManifest
+\$SUPPORT/camera/camera\-lifecycle/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.camera\.lifecycle\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :camera:camera-testing:externalNativeBuildDebug
+Build testing_surface_format_jni_armeabi\-v[0-9]+a
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/debug/armeabi\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/testing_surface_format_jni\.dir/surface_format_jni\.cpp\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/testing_surface_format_jni\.dir/jni_hooks\.cpp\.o
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/debug/obj/armeabi\-v[0-9]+a/libtesting_surface_format_jni\.so
+Build testing_surface_format_jni_arm[0-9]+\-v[0-9]+a
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/debug/arm[0-9]+\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/debug/obj/arm[0-9]+\-v[0-9]+a/libtesting_surface_format_jni\.so
+Build testing_surface_format_jni_x[0-9]+
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/debug/x[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/debug/obj/x[0-9]+/libtesting_surface_format_jni\.so
+Build testing_surface_format_jni_x[0-9]+_[0-9]+
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/debug/x[0-9]+_[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/debug/obj/x[0-9]+_[0-9]+/libtesting_surface_format_jni\.so
+# > Task :tipOfTreeDocsTask
+\$OUT_DIR/androidx/sqlite/sqlite\-inspection/build/generated/source/proto/release/java/androidx/sqlite/inspection/SqliteInspectorProtocol\.java:[0-9]+: error: cannot find symbol
+public static com\.google\.protobuf\.Internal\.EnumVerifier
+symbol: class EnumVerifier
+location: class Internal
+com\.google\.protobuf\.Internal\.EnumVerifier \{
+static final com\.google\.protobuf\.Internal\.EnumVerifier INSTANCE = new ErrorCodeVerifier\(\);
+\$OUT_DIR/androidx/work/work\-inspection/build/generated/source/proto/release/java/androidx/work/inspection/WorkManagerInspectorProtocol\.java:[0-9]+: error: cannot find symbol
+static final com\.google\.protobuf\.Internal\.EnumVerifier INSTANCE = new StateVerifier\(\);
+static final com\.google\.protobuf\.Internal\.EnumVerifier INSTANCE = new NetworkTypeVerifier\(\);
+\$SUPPORT/annotation/annotation\-experimental\-lint/integration\-tests/src/main/java/sample/UseJavaExperimentalFromJava\.java:[0-9]+: error: annotation value not of an allowable type
+@UseExperimental\(markerClass = \{ ExperimentalDateTime\.class, ExperimentalLocation\.class \}\)
+\$CHECKOUT/prebuilts/androidx/external/com/android/tools/external/com\-intellij/intellij\-core/[0-9]+\.[0-9]+\.[0-9]+/intellij\-core\-[0-9]+\.[0-9]+\.[0-9]+\.jar\(/javax/annotation/meta/TypeQualifierNickname\.java\):[0-9]+: lint: Invalid tag: @Documented \[[0-9]+\]
+\$CHECKOUT/prebuilts/androidx/external/com/android/tools/external/com\-intellij/intellij\-core/[0-9]+\.[0-9]+\.[0-9]+/intellij\-core\-[0-9]+\.[0-9]+\.[0-9]+\.jar\(/javax/annotation/meta/TypeQualifierNickname\.java\):[0-9]+: lint: Invalid tag: @TypeQualifierNickname \[[0-9]+\]
+\$CHECKOUT/prebuilts/androidx/external/com/android/tools/external/com\-intellij/intellij\-core/[0-9]+\.[0-9]+\.[0-9]+/intellij\-core\-[0-9]+\.[0-9]+\.[0-9]+\.jar\(/javax/annotation/meta/TypeQualifierNickname\.java\):[0-9]+: lint: Invalid tag: @Retention\(RetentionPolicy\.RUNTIME\) \[[0-9]+\]
+# > Task :camera:camera-camera2-pipe-integration:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/camera\-camera[0-9]+\-pipe\-integration_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :collection:collection-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/collection/collection\-benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.collection\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/collection/collection\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :camera:camera-extensions:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/camera/camera\-extensions/src/androidTest/java/androidx/camera/extensions/PreviewExtenderTest\.java uses unchecked or unsafe operations\.
+# > Task :camera:camera-camera2-pipe:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/camera\-camera[0-9]+\-pipe_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :customview:customview:processDebugAndroidTestManifest
+\$SUPPORT/customview/customview/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.customview\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :core:core-ktx:processDebugAndroidTestManifest
+\$SUPPORT/core/core\-ktx/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.core\.ktx\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :appsearch:appsearch:processDebugAndroidTestManifest
+\$SUPPORT/appsearch/appsearch/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.appsearch\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :customview:customview:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/customview/customview/src/androidTest/java/androidx/customview/widget/ExploreByTouchHelperTest\.java uses or overrides a deprecated API\.
+# > Task :datastore:datastore-core:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/datastore\-core_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :core:core:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/core/core/src/androidTest/java/androidx/core/content/pm/ShortcutManagerCompatTest\.java uses unchecked or unsafe operations\.
+# > Task :datastore:datastore-preferences:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/datastore\-preferences_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :core:core-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/core\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :drawerlayout:drawerlayout:processDebugAndroidTestManifest
+\$SUPPORT/drawerlayout/drawerlayout/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.drawerlayout\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :dynamicanimation:dynamicanimation:processDebugAndroidTestManifest
+\$SUPPORT/dynamic\-animation/dynamic\-animation/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.dynamicanimation\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :dynamicanimation:dynamicanimation-ktx:processDebugAndroidTestManifest
+\$SUPPORT/dynamic\-animation/dynamic\-animation\-ktx/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.dynamicanimation\.ktx\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :exifinterface:exifinterface:processDebugAndroidTestManifest
+\$SUPPORT/exifinterface/exifinterface/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.exifinterface\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :fragment:fragment-testing:processDebugAndroidTestManifest
+\$SUPPORT/fragment/fragment\-testing/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.fragment\.testing\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :appsearch:appsearch-local-backend:externalNativeBuildDebug
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/debug/armeabi\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX static library protobuf\-target/libprotobufd\.a
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/debug/obj/armeabi\-v[0-9]+a/libicing\.so
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/debug/arm[0-9]+\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/debug/obj/arm[0-9]+\-v[0-9]+a/libicing\.so
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/debug/x[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/debug/obj/x[0-9]+/libicing\.so
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/debug/x[0-9]+_[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/debug/obj/x[0-9]+_[0-9]+/libicing\.so
+# > Task :gridlayout:gridlayout:processDebugAndroidTestManifest
+\$SUPPORT/gridlayout/gridlayout/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.gridlayout\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :heifwriter:heifwriter:processDebugAndroidTestManifest
+\$SUPPORT/heifwriter/heifwriter/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.heifwriter\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :exifinterface:exifinterface:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/exifinterface/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest\.java uses or overrides a deprecated API\.
+Note: \$SUPPORT/exifinterface/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest\.java uses unchecked or unsafe operations\.
+# > Task :gridlayout:gridlayout:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/gridlayout/gridlayout/src/androidTest/java/androidx/gridlayout/widget/GridLayoutTest\.java uses or overrides a deprecated API\.
+# > Task :dynamicanimation:dynamicanimation-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/dynamicanimation\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :leanback:leanback:processDebugAndroidTestManifest
+\$SUPPORT/leanback/leanback/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.leanback\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\[:internal\-testutils\-runtime\] \$OUT_DIR/androidx/internal\-testutils\-runtime/build/intermediates/library_manifest/debug/AndroidManifest\.xml Warning:
+Package name 'androidx\.testutils' used in: :internal\-testutils\-runtime, :internal\-testutils\-espresso\.
+# > Task :leanback:leanback-tab:processDebugAndroidTestManifest
+\$SUPPORT/leanback/leanback\-tab/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.leanback\.tab\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :lifecycle:lifecycle-extensions:processDebugAndroidTestManifest
+\$SUPPORT/lifecycle/lifecycle\-extensions/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.lifecycle\.extensions\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :fragment:fragment-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/fragment\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :fragment:fragment-truth:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/fragment\-truth_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :inspection:inspection-testing:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/inspection\-testing_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :leanback:leanback:compileDebugAndroidTestJavaWithJavac
+warning: unknown enum constant AnnotationTarget\.CLASS
+reason: class file for kotlin\.annotation\.AnnotationTarget not found
+warning: unknown enum constant AnnotationTarget\.FUNCTION
+warning: unknown enum constant AnnotationRetention\.RUNTIME
+reason: class file for kotlin\.annotation\.AnnotationRetention not found
+# > Task :fragment:fragment-testing:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/fragment\-testing_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :leanback:leanback-paging:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/leanback\-paging_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :lifecycle:lifecycle-service:processDebugAndroidTestManifest
+\$SUPPORT/lifecycle/lifecycle\-service/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.lifecycle\.service\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :lifecycle:lifecycle-viewmodel-savedstate:processDebugAndroidTestManifest
+\$SUPPORT/lifecycle/lifecycle\-viewmodel\-savedstate/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.lifecycle\.viewmodel\.savedstate\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :leanback:leanback-tab:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/leanback/leanback\-tab/src/androidTest/java/androidx/leanback/tab/app/PagerAdapter\.java uses or overrides a deprecated API\.
+# > Task :lifecycle:lifecycle-runtime-testing:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/lifecycle\-runtime\-testing_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :lifecycle:lifecycle-runtime-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/lifecycle\-runtime\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :lifecycle:lifecycle-viewmodel-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/lifecycle\-viewmodel\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :lifecycle:lifecycle-livedata-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/lifecycle\-livedata\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :media2:media2-common:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/common/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.media[0-9]+\.common\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :media2:media2-player:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/player/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.media[0-9]+\.player\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :media2:media2-session:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/session/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.media[0-9]+\.session\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :media2:media2-common:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/media[0-9]+/common/src/androidTest/java/androidx/media[0-9]+/common/SubtitleDataTest\.java uses or overrides a deprecated API\.
+# > Task :navigation:navigation-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/navigation/benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.navigation\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/navigation/navigation\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :media2:media2-widget:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/widget/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.media[0-9]+\.widget\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :loader:loader-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/loader\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :navigation:navigation-dynamic-features-runtime:processDebugAndroidTestManifest
+\$SUPPORT/navigation/navigation\-dynamic\-features\-runtime/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.navigation\.dynamicfeatures\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :navigation:navigation-fragment:processDebugAndroidTestManifest
+Package name 'androidx\.testutils' used in: :internal\-testutils\-runtime, :internal\-testutils\-navigation\.
+# > Task :navigation:navigation-common-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-common\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :navigation:navigation-dynamic-features-fragment:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-dynamic\-features\-fragment_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :mediarouter:mediarouter:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/app/MediaRouteChooserDialogTest\.java uses or overrides a deprecated API\.
+# > Task :navigation:navigation-dynamic-features-runtime:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-dynamic\-features\-runtime_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :navigation:navigation-fragment-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-fragment\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :palette:palette:processDebugAndroidTestManifest
+\$SUPPORT/palette/palette/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.palette\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :percentlayout:percentlayout:processDebugAndroidTestManifest
+\$SUPPORT/percentlayout/percentlayout/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.percentlayout\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :preference:preference-ktx:processDebugAndroidTestManifest
+\$SUPPORT/preference/preference\-ktx/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.preference\.ktx\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :paging:paging-rxjava2:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/paging\-rxjava[0-9]+_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :navigation:navigation-runtime-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-runtime\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :navigation:navigation-runtime-truth:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-runtime\-truth_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :palette:palette-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/palette\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :navigation:navigation-testing:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-testing_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :paging:paging-runtime:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/paging\-runtime_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :recyclerview:recyclerview-benchmark:processReleaseAndroidTestManifest
+\$OUT_DIR/androidx/recyclerview/recyclerview\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :recyclerview:recyclerview-selection:processDebugAndroidTestManifest
+\$SUPPORT/recyclerview/recyclerview\-selection/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.recyclerview\.selection\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :preference:preference:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/preference/preference/src/androidTest/java/androidx/preference/tests/PreferenceDataStoreTest\.java uses unchecked or unsafe operations\.
+# > Task :remotecallback:remotecallback:processDebugAndroidTestManifest
+\$SUPPORT/remotecallback/remotecallback/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.remotecallback\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :preference:preference-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/preference\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :recyclerview:recyclerview-selection:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/recyclerview/recyclerview\-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest\.java uses or overrides a deprecated API\.
+# > Task :savedstate:savedstate:processDebugAndroidTestManifest
+\$SUPPORT/savedstate/savedstate/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.savedstate\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :room:room-benchmark:processReleaseAndroidTestManifest
+\$OUT_DIR/androidx/room/room\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :savedstate:savedstate-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/savedstate\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :room:room-runtime:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/room/runtime/src/androidTest/java/androidx/room/migration/TableInfoTest\.java uses unchecked or unsafe operations\.
+# > Task :room:room-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/room\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :room:room-benchmark:kaptReleaseAndroidTestKotlin
+\$OUT_DIR/androidx/room/room\-benchmark/build/tmp/kapt[0-9]+/stubs/releaseAndroidTest/androidx/room/benchmark/RelationBenchmark\.java:[0-9]+: warning: The return value includes a POJO with a @Relation\. It is usually desired to annotate this method with @Transaction to avoid possibility of inconsistent results between the POJO and its relations\. See https://developer\.android\.com/reference/androidx/room/Transaction\.html for details\.
+public abstract java\.util\.List<androidx\.room\.benchmark\.RelationBenchmark\.UserWithItems> getUserWithItems\(\);
+# > Task :sharetarget:sharetarget:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/sharetarget/sharetarget/src/androidTest/java/androidx/sharetarget/ChooserTargetServiceCompatTest\.java uses or overrides a deprecated API\.
+Note: \$SUPPORT/sharetarget/sharetarget/src/androidTest/java/androidx/sharetarget/ChooserTargetServiceCompatTest\.java uses unchecked or unsafe operations\.
+# > Task :security:security-crypto-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/security\-crypto\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :appsearch:appsearch-local-backend:processDebugAndroidTestManifest
+\$SUPPORT/appsearch/local\-backend/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.appsearch\.localbackend\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :textclassifier:textclassifier:processDebugAndroidTestManifest
+\$SUPPORT/textclassifier/textclassifier/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.textclassifier\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :transition:transition:processDebugAndroidTestManifest
+\$SUPPORT/transition/transition/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.transition\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :transition:transition-ktx:processDebugAndroidTestManifest
+\$SUPPORT/transition/transition\-ktx/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.transition\.ktx\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :tvprovider:tvprovider:processDebugAndroidTestManifest
+\$SUPPORT/tv\-provider/tv\-provider/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.tvprovider\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :wear:wear:processDebugAndroidTestManifest
+\$SUPPORT/wear/wear/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.wear\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :vectordrawable:vectordrawable:processDebugAndroidTestManifest
+\$SUPPORT/vectordrawable/vectordrawable/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.vectordrawable\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :viewpager:viewpager:processDebugAndroidTestManifest
+\$SUPPORT/viewpager/viewpager/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.viewpager\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :vectordrawable:vectordrawable-animated:processDebugAndroidTestManifest
+\$SUPPORT/vectordrawable/vectordrawable\-animated/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.vectordrawable\.animated\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :vectordrawable:vectordrawable-seekable:processDebugAndroidTestManifest
+\$SUPPORT/vectordrawable/vectordrawable\-seekable/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.vectordrawable\.seekable\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :viewpager2:viewpager2:processDebugAndroidTestManifest
+\$SUPPORT/viewpager[0-9]+/viewpager[0-9]+/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.viewpager[0-9]+\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+Package name 'androidx\.testutils' used in: :internal\-testutils\-appcompat, :internal\-testutils\-runtime, :internal\-testutils\-espresso\.
+# > Task :transition:transition-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/transition\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :wear:wear-watchface:processDebugAndroidTestManifest
+\$SUPPORT/wear/wear\-watchface/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.wear\.watchface\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :window:window:processDebugAndroidTestManifest
+\$SUPPORT/window/window/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.window\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :webkit:webkit:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatForceDarkTest\.java uses or overrides a deprecated API\.
+# > Task :wear:wear-watchface:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/wear\-watchface_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :work:work-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/work/workmanager\-benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.work\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/work/work\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :work:work-inspection:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/work\-inspection_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :work:work-runtime-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/work\-runtime\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :benchmark:integration-tests:dry-run-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/benchmark/integration\-tests/dry\-run\-benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.benchmark\.integration\.dryrun\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/benchmark/integration\-tests/dry\-run\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :benchmark:integration-tests:startup-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/benchmark/integration\-tests/startup\-benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.benchmark\.integration\.startup\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/benchmark/integration\-tests/startup\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :work:work-testing:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/work\-testing_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :camera:integration-tests:camera-testapp-core:externalNativeBuildDebug
+Build opengl_renderer_jni_armeabi\-v[0-9]+a
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/debug/armeabi\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/opengl_renderer_jni\.dir/jni_hooks\.cpp\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/opengl_renderer_jni\.dir/opengl_renderer_jni\.cpp\.o
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/debug/obj/armeabi\-v[0-9]+a/libopengl_renderer_jni\.so
+Build opengl_renderer_jni_arm[0-9]+\-v[0-9]+a
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/debug/arm[0-9]+\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/debug/obj/arm[0-9]+\-v[0-9]+a/libopengl_renderer_jni\.so
+Build opengl_renderer_jni_x[0-9]+
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/debug/x[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/debug/obj/x[0-9]+/libopengl_renderer_jni\.so
+Build opengl_renderer_jni_x[0-9]+_[0-9]+
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/debug/x[0-9]+_[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/debug/obj/x[0-9]+_[0-9]+/libopengl_renderer_jni\.so
+# > Task :camera:integration-tests:camera-testapp-extensions:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/camera/integration\-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ToggleButtonTest\.java uses or overrides a deprecated API\.
+# > Task :camera:integration-tests:camera-testapp-camera2-pipe:minifyReleaseWithR8
+R[0-9]+: Missing class: java\.lang\.instrument\.ClassFileTransformer
+R[0-9]+: Missing class: sun\.misc\.SignalHandler
+# > Task :camera:integration-tests:camera-testapp-view:minifyReleaseWithR8
+R[0-9]+: Missing class: java\.lang\.ClassValue
+# > Task :camera:integration-tests:camera-testapp-core:externalNativeBuildRelease
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/release/armeabi\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/release/obj/armeabi\-v[0-9]+a/libopengl_renderer_jni\.so
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/release/arm[0-9]+\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/release/obj/arm[0-9]+\-v[0-9]+a/libopengl_renderer_jni\.so
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/release/x[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/release/obj/x[0-9]+/libopengl_renderer_jni\.so
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/release/x[0-9]+_[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/release/obj/x[0-9]+_[0-9]+/libopengl_renderer_jni\.so
+# > Task :room:integration-tests:room-testapp-noappcompat:compileDebugAndroidTestJavaWithJavac
+\$SUPPORT/room/integration\-tests/noappcompattestapp/src/androidTest/java/androidx/room/integration/noappcompat/BareRelationDatabaseTest\.java:[0-9]+: warning: The return value includes a POJO with a @Relation\. It is usually desired to annotate this method with @Transaction to avoid possibility of inconsistent results between the POJO and its relations\. See https://developer\.android\.com/reference/androidx/room/Transaction\.html for details\.
+UserAndPets getUserWithPets\(long id\);
+List<UserAndPet> getUsersWithPet\(\);
+# > Task :textclassifier:integration-tests:testapp:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/textclassifier/integration\-tests/testapp/src/androidTest/java/androidx/textclassifier/integration/testapp/MainActivityTest\.java uses or overrides a deprecated API\.
+# > Task :room:integration-tests:room-testapp:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/room/integration\-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/TestUtil\.java uses unchecked or unsafe operations\.
+# > Task :hilt:integration-tests:hilt-testapp-worker:kaptDebugAndroidTestKotlin
+warning: The following options were not recognized by any processor: '\[dagger\.hilt\.android\.internal\.disableAndroidSuperclassValidation, kapt\.kotlin\.generated\]'
+# > Task :hilt:integration-tests:hilt-testapp-viewmodel:compileReleaseJavaWithJavac
+Note: \$OUT_DIR/androidx/hilt/integration\-tests/hilt\-testapp\-viewmodel/build/generated/source/kapt/release/androidx/hilt/integration/viewmodelapp/Hilt_SimpleFragment\.java uses or overrides a deprecated API\.
+# > Task :slice-core:generateApi
+src/main/java/androidx/slice/compat/SliceProviderCompat\.java:[0-9]+: warning: Parameter permissionManager references hidden type androidx\.slice\.compat\.CompatPermissionManager\. \[HiddenTypeParameter\]
+# > Task :appsearch:appsearch-compiler:lint
+\$SUPPORT/appsearch/compiler/lint\-baseline\.xml: Information: [0-9]+ error was filtered out because it is listed in the baseline file, lint\-baseline\.xml
+\[LintBaseline\]
+[0-9]+ errors, [0-9]+ warnings \([0-9]+ error filtered by baseline lint\-baseline\.xml\)
+# > Task :slice-view:generateApi
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of hidden type SliceContent in androidx\.slice\.widget\.ListContent\.getListHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceStyle in androidx\.slice\.widget\.ListContent\.getHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceViewPolicy in androidx\.slice\.widget\.ListContent\.getHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceStyle in androidx\.slice\.widget\.ListContent\.getRowItems\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceViewPolicy in androidx\.slice\.widget\.ListContent\.getRowItems\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Method androidx\.slice\.widget\.ListContent\.getSeeMoreItem returns unavailable type SliceContent \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceContent in androidx\.slice\.widget\.ListContent\.getRowType\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceStyle in androidx\.slice\.widget\.ListContent\.getListHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceViewPolicy in androidx\.slice\.widget\.ListContent\.getListHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/GridContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceStyle in androidx\.slice\.widget\.GridContent\.getHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/GridContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceViewPolicy in androidx\.slice\.widget\.GridContent\.getHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/RowContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceStyle in androidx\.slice\.widget\.RowContent\.getHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/RowContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceViewPolicy in androidx\.slice\.widget\.RowContent\.getHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/GridContent\.java:[0-9]+: warning: Parameter style references hidden type androidx\.slice\.widget\.SliceStyle\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/GridContent\.java:[0-9]+: warning: Parameter policy references hidden type androidx\.slice\.widget\.SliceViewPolicy\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter style references hidden type androidx\.slice\.widget\.SliceStyle\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter policy references hidden type androidx\.slice\.widget\.SliceViewPolicy\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter listItems references hidden type class androidx\.slice\.widget\.SliceContent\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Method androidx\.slice\.widget\.ListContent\.getRowItems\(int, androidx\.slice\.widget\.SliceStyle, androidx\.slice\.widget\.SliceViewPolicy\) references hidden type class androidx\.slice\.widget\.SliceContent\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Method androidx\.slice\.widget\.ListContent\.getRowItems\(\) references hidden type class androidx\.slice\.widget\.SliceContent\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter content references hidden type androidx\.slice\.widget\.SliceContent\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Method androidx\.slice\.widget\.ListContent\.getSeeMoreItem\(\) references hidden type androidx\.slice\.widget\.SliceContent\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/RowContent\.java:[0-9]+: warning: Parameter style references hidden type androidx\.slice\.widget\.SliceStyle\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/RowContent\.java:[0-9]+: warning: Parameter policy references hidden type androidx\.slice\.widget\.SliceViewPolicy\. \[HiddenTypeParameter\]
+# > Task :appcompat:appcompat-resources:generateApi
+src/main/java/androidx/appcompat/widget/ResourceManagerInternal\.java:[0-9]+: warning: Parameter hooks references hidden type androidx\.appcompat\.widget\.ResourceManagerInternal\.ResourceManagerHooks\. \[HiddenTypeParameter\]
+# > Task :arch:core-common:generateApi
+src/main/java/androidx/arch/core/internal/FastSafeIterableMap\.java:[0-9]+: warning: Method androidx\.arch\.core\.internal\.FastSafeIterableMap\.get\(K\) references hidden type androidx\.arch\.core\.internal\.SafeIterableMap\.Entry<K,V>\. \[HiddenTypeParameter\]
+src/main/java/androidx/arch/core/internal/SafeIterableMap\.java:[0-9]+: warning: Method androidx\.arch\.core\.internal\.SafeIterableMap\.get\(K\) references hidden type androidx\.arch\.core\.internal\.SafeIterableMap\.Entry<K,V>\. \[HiddenTypeParameter\]
+src/main/java/androidx/arch/core/internal/SafeIterableMap\.java:[0-9]+: warning: Method androidx\.arch\.core\.internal\.SafeIterableMap\.iteratorWithAdditions\(\) references hidden type androidx\.arch\.core\.internal\.SafeIterableMap\.IteratorWithAdditions\. \[HiddenTypeParameter\]
+src/main/java/androidx/arch/core/internal/SafeIterableMap\.java:[0-9]+: warning: Method androidx\.arch\.core\.internal\.SafeIterableMap\.put\(K, V\) references hidden type androidx\.arch\.core\.internal\.SafeIterableMap\.Entry<K,V>\. \[HiddenTypeParameter\]
+# > Task :appcompat:appcompat:generateApi
+src/main/java/androidx/appcompat/view/menu/MenuPopupHelper\.java:[0-9]+: warning: Method androidx\.appcompat\.view\.menu\.MenuPopupHelper\.getPopup\(\) references hidden type androidx\.appcompat\.view\.menu\.MenuPopup\. \[HiddenTypeParameter\]
+src/main/java/androidx/appcompat/widget/ActionMenuView\.java:[0-9]+: warning: Parameter presenter references hidden type androidx\.appcompat\.widget\.ActionMenuPresenter\. \[HiddenTypeParameter\]
+src/main/java/androidx/appcompat/widget/ActivityChooserView\.java:[0-9]+: warning: Method androidx\.appcompat\.widget\.ActivityChooserView\.getDataModel\(\) references hidden type androidx\.appcompat\.widget\.ActivityChooserModel\. \[HiddenTypeParameter\]
+src/main/java/androidx/appcompat/widget/ActivityChooserView\.java:[0-9]+: warning: Parameter dataModel references hidden type androidx\.appcompat\.widget\.ActivityChooserModel\. \[HiddenTypeParameter\]
+src/main/java/androidx/appcompat/widget/Toolbar\.java:[0-9]+: warning: Parameter outerPresenter references hidden type androidx\.appcompat\.widget\.ActionMenuPresenter\. \[HiddenTypeParameter\]
+# > Task :core:core-appdigest:processDebugAndroidTestManifest
+\$SUPPORT/core/core\-appdigest/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.core\.appdigest\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :core:core:generateApi
+src\/main\/java\/androidx\/core\/app\/NotificationCompat\.java\:[0-9]+\: warning\: Builder constructor arguments must be mandatory \(i\.e\. not \@Nullable\)\: parameter title in androidx\.core\.app\.NotificationCompat\.Action\.Builder\(int icon\, CharSequence title\, android\.app\.PendingIntent intent\) \[OptionalBuilderConstructorArgument\]See tools\/metalava\/API\-LINT\.md for how to handle these\.
+src/main/java/androidx/core/app/NotificationCompat\.java:[0-9]+: warning: Builder constructor arguments must be mandatory \(i\.e\. not @Nullable\): parameter title in androidx\.core\.app\.NotificationCompat\.Action\.Builder\(int icon, CharSequence title, android\.app\.PendingIntent intent\) \[OptionalBuilderConstructorArgument\]
+src/main/java/androidx/core/app/NotificationCompat\.java:[0-9]+: warning: Builder constructor arguments must be mandatory \(i\.e\. not @Nullable\): parameter intent in androidx\.core\.app\.NotificationCompat\.Action\.Builder\(int icon, CharSequence title, android\.app\.PendingIntent intent\) \[OptionalBuilderConstructorArgument\]
+[0-9]+ new API lint issues were found\.
+See tools/metalava/API\-LINT\.md for how to handle these\.
+# > Task :cursoradapter:cursoradapter:generateApi
+src/main/java/androidx/cursoradapter/widget/CursorAdapter\.java:[0-9]+: warning: Field CursorAdapter\.mChangeObserver references hidden type androidx\.cursoradapter\.widget\.CursorAdapter\.ChangeObserver\. \[HiddenTypeParameter\]
+src/main/java/androidx/cursoradapter/widget/CursorAdapter\.java:[0-9]+: warning: Field CursorAdapter\.mCursorFilter references hidden type androidx\.cursoradapter\.widget\.CursorFilter\. \[HiddenTypeParameter\]
+# > Task :camera:camera-testing:externalNativeBuildRelease
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/release/armeabi\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/release/obj/armeabi\-v[0-9]+a/libtesting_surface_format_jni\.so
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/release/arm[0-9]+\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/release/obj/arm[0-9]+\-v[0-9]+a/libtesting_surface_format_jni\.so
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/release/x[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/release/obj/x[0-9]+/libtesting_surface_format_jni\.so
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/release/x[0-9]+_[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/release/obj/x[0-9]+_[0-9]+/libtesting_surface_format_jni\.so
+# > Task :camera:camera-camera2:runErrorProne
+\$SUPPORT/camera/camera\-camera[0-9]+/src/main/java/androidx/camera/camera[0-9]+/internal/SupportedSizeConstraints\.java:[0-9]+: warning: \[AutoValueImmutableFields\] AutoValue instances should be deeply immutable\. Therefore, we recommend returning ImmutableSet instead\. Read more at http://goo\.gl/qWo[0-9]+sC
+public abstract Set<Integer> getAffectedFormats\(\);
+\(see https://errorprone\.info/bugpattern/AutoValueImmutableFields\)
+\$SUPPORT/camera/camera\-camera[0-9]+/src/main/java/androidx/camera/camera[0-9]+/internal/SupportedSizeConstraints\.java:[0-9]+: warning: \[AutoValueImmutableFields\] AutoValue instances should be deeply immutable\. Therefore, we recommend returning ImmutableList instead\. Read more at http://goo\.gl/qWo[0-9]+sC
+public abstract List<Size> getExcludedSizes\(\);
+# > Task :leanback:leanback:generateApi
+src/main/java/androidx/leanback/transition/TransitionHelper\.java:[0-9]+: warning: Parameter of unavailable type androidx\.leanback\.transition\.TransitionEpicenterCallback in androidx\.leanback\.transition\.TransitionHelper\.setEpicenterCallback\(\) \[UnavailableSymbol\]
+src/main/java/androidx/leanback/transition/TransitionHelper\.java:[0-9]+: warning: Parameter callback references hidden type androidx\.leanback\.transition\.TransitionEpicenterCallback\. \[HiddenTypeParameter\]
+# > Task :media:media:generateApi
+src/main/java/android/support/v[0-9]+/media/session/MediaControllerCompat\.java:[0-9]+: warning: Method android\.support\.v[0-9]+\.media\.session\.MediaControllerCompat\.Callback\.getIControllerCallback returns unavailable type IMediaControllerCallback \[UnavailableSymbol\]
+src/main/java/android/support/v[0-9]+/media/session/MediaControllerCompat\.java:[0-9]+: warning: Method android\.support\.v[0-9]+\.media\.session\.MediaControllerCompat\.Callback\.getIControllerCallback\(\) references hidden type android\.support\.v[0-9]+\.media\.session\.IMediaControllerCallback\. \[HiddenTypeParameter\]
+# > Task :remotecallback:remotecallback-processor:lint
+\$SUPPORT/remotecallback/processor/lint\-baseline\.xml: Information: [0-9]+ error was filtered out because it is listed in the baseline file, lint\-baseline\.xml
+# > Task :core:core:runErrorProne
+\$SUPPORT/core/core/src/main/java/androidx/core/content/pm/ShortcutManagerCompat\.java:[0-9]+: warning: \[ModifyCollectionInEnhancedForLoop\] Modifying a collection while iterating over it in a loop may cause a ConcurrentModificationException to be thrown\.
+shortcutInfoList\.remove\(info\);
+\(see https://errorprone\.info/bugpattern/ModifyCollectionInEnhancedForLoop\)
+# > Task :versionedparcelable:versionedparcelable-compiler:lint
+\$SUPPORT/versionedparcelable/versionedparcelable\-compiler/lint\-baseline\.xml: Information: [0-9]+ error was filtered out because it is listed in the baseline file, lint\-baseline\.xml
+# > Task :textclassifier:textclassifier:generateApi
+src/main/java/androidx/textclassifier/widget/ToolbarController\.java:[0-9]+: warning: Method androidx\.textclassifier\.widget\.ToolbarController\.FloatingToolbarFactory\.create returns unavailable type IFloatingToolbar \[UnavailableSymbol\]
+src/main/java/androidx/textclassifier/widget/ToolbarController\.java:[0-9]+: warning: Method androidx\.textclassifier\.widget\.ToolbarController\.FloatingToolbarFactory\.create\(android\.widget\.TextView\) references hidden type androidx\.textclassifier\.widget\.IFloatingToolbar\. \[HiddenTypeParameter\]
+# > Task :transition:transition:generateApi
+src/main/java/androidx/transition/Transition\.java:[0-9]+: warning: Parameter startValues references hidden type androidx\.transition\.TransitionValuesMaps\. \[HiddenTypeParameter\]
+src/main/java/androidx/transition/Transition\.java:[0-9]+: warning: Parameter endValues references hidden type androidx\.transition\.TransitionValuesMaps\. \[HiddenTypeParameter\]
+src/main/java/androidx/transition/TransitionSet\.java:[0-9]+: warning: Parameter startValues references hidden type androidx\.transition\.TransitionValuesMaps\. \[HiddenTypeParameter\]
+src/main/java/androidx/transition/TransitionSet\.java:[0-9]+: warning: Parameter endValues references hidden type androidx\.transition\.TransitionValuesMaps\. \[HiddenTypeParameter\]
+# > Task :activity:integration-tests:testapp:processDebugAndroidTestManifest
+\$SUPPORT/activity/integration\-tests/testapp/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.activity\.integration\.testapp\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :room:integration-tests:room-testapp-autovalue:compileDebugAndroidTestJavaWithJavac
+Stream closed
+# > Task :benchmark:benchmark-macro:processDebugAndroidTestManifest
+\$SUPPORT\/benchmark\/macro\/src\/androidTest\/AndroidManifest\.xml Warning\:
+Package name \'androidx\.benchmark\.macro\.test\' used in\: AndroidManifest\.xml\, manifestMerger[0-9]+\.xml\.
diff --git a/development/build_log_simplifier/test.py b/development/build_log_simplifier/test.py
index 57ab11d..d59aa4a 100755
--- a/development/build_log_simplifier/test.py
+++ b/development/build_log_simplifier/test.py
@@ -19,6 +19,7 @@
from build_log_simplifier import generate_suggested_exemptions
from build_log_simplifier import normalize_paths
from build_log_simplifier import regexes_matcher
+from build_log_simplifier import remove_control_characters
import re
def fail(message):
@@ -54,7 +55,7 @@
actual = normalize_paths(lines)
if expected_normalized != actual:
fail("test_normalize_paths returned incorrect response.\n" +
- "Input: " + str(lines) + "\n" +
+ "Input: " + str(lines) + "\n" +
"Output: " + str(actual) + "\n" +
"Expected output: " + str(expected_normalized)
)
@@ -287,6 +288,26 @@
if (actual != expected):
fail("collapse_tasks_having_no_output gave incorrect error. Expected: " + str(expected) + ", actual = " + str(actual))
+def test_remove_control_characters():
+ print("test_remove_control_characters")
+ given = [
+ # a line starting with several color codes in it
+ "[1msrc/main/java/androidx/arch/core/internal/FastSafeIterableMap.java:39: [33mwarning: [0mMethod androidx.arch.core.internal.FastSafeIterableMap.get(K) references hidden type androidx.arch.core.internal.SafeIterableMap.Entry<K,V>. [HiddenTypeParameter]",
+ # a line with a variety of characters, none of which are color codes
+ "space tab\tCAPITAL underscore_ slash/ colon: number 1 newline\n",
+ ]
+ expected = [
+ "src/main/java/androidx/arch/core/internal/FastSafeIterableMap.java:39: warning: Method androidx.arch.core.internal.FastSafeIterableMap.get(K) references hidden type androidx.arch.core.internal.SafeIterableMap.Entry<K,V>. [HiddenTypeParameter]",
+ "space tab\tCAPITAL underscore_ slash/ colon: number 1 newline\n",
+ ]
+ actual = [remove_control_characters(line) for line in given]
+ if actual != expected:
+ fail("remove_control_charactres gave incorrect response.\n\n" +
+ "Input : " + str(given) + ".\n\n" +
+ "Expected output: " + str(expected) + ".\n\n" +
+ "Actual output : " + str(actual) + ".")
+
+
def main():
test_collapse_consecutive_blank_lines()
test_collapse_tasks_having_no_output()
@@ -294,6 +315,7 @@
test_normalize_paths()
test_regexes_matcher_get_matching_regexes()
test_regexes_matcher_index_first_matching_regex()
+ test_remove_control_characters()
if __name__ == "__main__":
main()
diff --git a/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java b/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
index ec9ce09..28f3f93 100644
--- a/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
+++ b/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
@@ -24,6 +24,7 @@
import android.media.MediaDataSource;
import android.media.MediaMetadataRetriever;
import android.os.Build;
+import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import android.util.Log;
@@ -32,6 +33,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import java.io.BufferedInputStream;
@@ -67,7 +69,6 @@
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
-import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -3946,12 +3947,8 @@
// Keep the original file descriptor in order to save attributes when it's seekable.
// Otherwise, just close the given file descriptor after reading it because the save
// feature won't be working.
- try {
- fileDescriptor = Os.dup(fileDescriptor);
- isFdDuped = true;
- } catch (Exception e) {
- throw new IOException("Failed to duplicate file descriptor", e);
- }
+ fileDescriptor = OsApi21Impl.dup(fileDescriptor);
+ isFdDuped = true;
} else {
mSeekableFileDescriptor = null;
}
@@ -4607,7 +4604,7 @@
private static boolean isSeekableFD(FileDescriptor fd) {
if (Build.VERSION.SDK_INT >= 21) {
try {
- Os.lseek(fd, 0, OsConstants.SEEK_CUR);
+ OsApi21Impl.lseek(fd, 0, OsConstants.SEEK_CUR);
return true;
} catch (Exception e) {
if (DEBUG) {
@@ -4667,28 +4664,18 @@
FileInputStream in = null;
FileOutputStream out = null;
- File originalFile = null;
- if (mFilename != null) {
- originalFile = new File(mFilename);
- }
File tempFile = null;
try {
- // Move the original file to temporary file.
+ // Copy the original file to temporary file.
+ tempFile = File.createTempFile("temp", "tmp");
if (mFilename != null) {
- String parent = originalFile.getParent();
- String name = originalFile.getName();
- String tempPrefix = UUID.randomUUID().toString() + "_";
- tempFile = new File(parent, tempPrefix + name);
- if (!originalFile.renameTo(tempFile)) {
- throw new IOException("Couldn't rename to " + tempFile.getAbsolutePath());
- }
+ in = new FileInputStream(mFilename);
} else if (Build.VERSION.SDK_INT >= 21 && mSeekableFileDescriptor != null) {
- tempFile = File.createTempFile("temp", "tmp");
- Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
+ OsApi21Impl.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
in = new FileInputStream(mSeekableFileDescriptor);
- out = new FileOutputStream(tempFile);
- copy(in, out);
}
+ out = new FileOutputStream(tempFile);
+ copy(in, out);
} catch (Exception e) {
throw new IOException("Failed to copy original file to temp file", e);
} finally {
@@ -4706,7 +4693,7 @@
if (mFilename != null) {
out = new FileOutputStream(mFilename);
} else if (Build.VERSION.SDK_INT >= 21 && mSeekableFileDescriptor != null) {
- Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
+ OsApi21Impl.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
out = new FileOutputStream(mSeekableFileDescriptor);
}
bufferedIn = new BufferedInputStream(in);
@@ -4719,12 +4706,26 @@
saveWebpAttributes(bufferedIn, bufferedOut);
}
} catch (Exception e) {
+ // Restore original file
+ closeQuietly(bufferedIn);
+ closeQuietly(bufferedOut);
+ in = new FileInputStream(tempFile);
if (mFilename != null) {
- if (!tempFile.renameTo(originalFile)) {
- throw new IOException("Couldn't restore original file: "
- + originalFile.getAbsolutePath());
+ out = new FileOutputStream(mFilename);
+ } else if (Build.VERSION.SDK_INT >= 21 && mSeekableFileDescriptor != null) {
+ try {
+ OsApi21Impl.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
+ // Catching ErrnoException will raise error in API < 21
+ } catch (Exception exception) {
+ throw new IOException("Failed to save new file. Original file may be "
+ + "corrupted since error occurred while trying to restore it.",
+ exception);
}
+ out = new FileOutputStream(mSeekableFileDescriptor);
}
+ copy(in, out);
+ closeQuietly(in);
+ closeQuietly(out);
throw new IOException("Failed to save new file", e);
} finally {
closeQuietly(bufferedIn);
@@ -4794,8 +4795,8 @@
} else if (mFilename != null) {
in = new FileInputStream(mFilename);
} else if (Build.VERSION.SDK_INT >= 21 && mSeekableFileDescriptor != null) {
- newFileDescriptor = Os.dup(mSeekableFileDescriptor);
- Os.lseek(newFileDescriptor, 0, OsConstants.SEEK_SET);
+ newFileDescriptor = OsApi21Impl.dup(mSeekableFileDescriptor);
+ OsApi21Impl.lseek(newFileDescriptor, 0, OsConstants.SEEK_SET);
in = new FileInputStream(newFileDescriptor);
}
if (in == null) {
@@ -7985,12 +7986,7 @@
// Os.dup and Os.close was introduced in API 21 so this method shouldn't be called
// in API < 21.
if (Build.VERSION.SDK_INT >= 21) {
- try {
- Os.close(fd);
- // Catching ErrnoException will raise error in API < 21
- } catch (Exception ex) {
- Log.e(TAG, "Error closing fd.");
- }
+ OsApi21Impl.close(fd);
} else {
Log.e(TAG, "closeFileDescriptor is called in API < 21, which must be wrong.");
}
@@ -8078,4 +8074,39 @@
}
return false;
}
+
+ /**
+ * Nested class to avoid verification errors for methods introduced in Android 5.0 (API 21).
+ */
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+ private static class OsApi21Impl {
+ // Prevent instantiation.
+ private OsApi21Impl() {}
+
+ static FileDescriptor dup(FileDescriptor fd) throws IOException {
+ FileDescriptor duplicateFD = null;
+ try {
+ duplicateFD = Os.dup(fd);
+ } catch (ErrnoException e) {
+ throw new IOException("Failed to duplicate file descriptor", e);
+ }
+ return duplicateFD;
+ }
+
+ static void close(FileDescriptor fd) {
+ try {
+ Os.close(fd);
+ } catch (ErrnoException ex) {
+ Log.e(TAG, "Error closing fd.");
+ }
+ }
+
+ static void lseek(FileDescriptor fd, int offset, int osConstant) throws IOException {
+ try {
+ Os.lseek(fd, offset, osConstant);
+ } catch (ErrnoException e) {
+ throw new IOException("Failed to seek file descriptor", e);
+ }
+ }
+ }
}
diff --git a/fragment/fragment-ktx/api/1.3.0-beta01.txt b/fragment/fragment-ktx/api/1.3.0-beta01.txt
new file mode 100644
index 0000000..d3e6dff
--- /dev/null
+++ b/fragment/fragment-ktx/api/1.3.0-beta01.txt
@@ -0,0 +1,34 @@
+// Signature format: 3.0
+package androidx.fragment.app {
+
+ public final class FragmentKt {
+ method public static void clearFragmentResult(androidx.fragment.app.Fragment, String requestKey);
+ method public static void clearFragmentResultListener(androidx.fragment.app.Fragment, String requestKey);
+ method public static void setFragmentResult(androidx.fragment.app.Fragment, String requestKey, android.os.Bundle result);
+ method public static void setFragmentResultListener(androidx.fragment.app.Fragment, String requestKey, kotlin.jvm.functions.Function2<? super java.lang.String,? super android.os.Bundle,kotlin.Unit> listener);
+ }
+
+ public final class FragmentManagerKt {
+ method public static inline void commit(androidx.fragment.app.FragmentManager, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+ method public static inline void commitNow(androidx.fragment.app.FragmentManager, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+ method @Deprecated public static inline void transaction(androidx.fragment.app.FragmentManager, boolean now = false, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+ }
+
+ public final class FragmentTransactionKt {
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! add(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, String tag = null, android.os.Bundle? args = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! add(androidx.fragment.app.FragmentTransaction, String tag, android.os.Bundle? args = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! replace(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, String tag = null, android.os.Bundle? args = null);
+ }
+
+ public final class FragmentViewModelLazyKt {
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! activityViewModels(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+ method @MainThread public static <VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> createViewModelLazy(androidx.fragment.app.Fragment, kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! viewModels(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer = { return this }, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+ }
+
+ public final class ViewKt {
+ method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+ }
+
+}
+
diff --git a/fragment/fragment-ktx/api/public_plus_experimental_1.3.0-beta01.txt b/fragment/fragment-ktx/api/public_plus_experimental_1.3.0-beta01.txt
new file mode 100644
index 0000000..d3e6dff
--- /dev/null
+++ b/fragment/fragment-ktx/api/public_plus_experimental_1.3.0-beta01.txt
@@ -0,0 +1,34 @@
+// Signature format: 3.0
+package androidx.fragment.app {
+
+ public final class FragmentKt {
+ method public static void clearFragmentResult(androidx.fragment.app.Fragment, String requestKey);
+ method public static void clearFragmentResultListener(androidx.fragment.app.Fragment, String requestKey);
+ method public static void setFragmentResult(androidx.fragment.app.Fragment, String requestKey, android.os.Bundle result);
+ method public static void setFragmentResultListener(androidx.fragment.app.Fragment, String requestKey, kotlin.jvm.functions.Function2<? super java.lang.String,? super android.os.Bundle,kotlin.Unit> listener);
+ }
+
+ public final class FragmentManagerKt {
+ method public static inline void commit(androidx.fragment.app.FragmentManager, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+ method public static inline void commitNow(androidx.fragment.app.FragmentManager, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+ method @Deprecated public static inline void transaction(androidx.fragment.app.FragmentManager, boolean now = false, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+ }
+
+ public final class FragmentTransactionKt {
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! add(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, String tag = null, android.os.Bundle? args = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! add(androidx.fragment.app.FragmentTransaction, String tag, android.os.Bundle? args = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! replace(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, String tag = null, android.os.Bundle? args = null);
+ }
+
+ public final class FragmentViewModelLazyKt {
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! activityViewModels(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+ method @MainThread public static <VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> createViewModelLazy(androidx.fragment.app.Fragment, kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! viewModels(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer = { return this }, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+ }
+
+ public final class ViewKt {
+ method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+ }
+
+}
+
diff --git a/fragment/fragment-ktx/api/res-1.3.0-beta01.txt b/fragment/fragment-ktx/api/res-1.3.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fragment/fragment-ktx/api/res-1.3.0-beta01.txt
diff --git a/fragment/fragment-ktx/api/restricted_1.3.0-beta01.txt b/fragment/fragment-ktx/api/restricted_1.3.0-beta01.txt
new file mode 100644
index 0000000..d3e6dff
--- /dev/null
+++ b/fragment/fragment-ktx/api/restricted_1.3.0-beta01.txt
@@ -0,0 +1,34 @@
+// Signature format: 3.0
+package androidx.fragment.app {
+
+ public final class FragmentKt {
+ method public static void clearFragmentResult(androidx.fragment.app.Fragment, String requestKey);
+ method public static void clearFragmentResultListener(androidx.fragment.app.Fragment, String requestKey);
+ method public static void setFragmentResult(androidx.fragment.app.Fragment, String requestKey, android.os.Bundle result);
+ method public static void setFragmentResultListener(androidx.fragment.app.Fragment, String requestKey, kotlin.jvm.functions.Function2<? super java.lang.String,? super android.os.Bundle,kotlin.Unit> listener);
+ }
+
+ public final class FragmentManagerKt {
+ method public static inline void commit(androidx.fragment.app.FragmentManager, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+ method public static inline void commitNow(androidx.fragment.app.FragmentManager, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+ method @Deprecated public static inline void transaction(androidx.fragment.app.FragmentManager, boolean now = false, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+ }
+
+ public final class FragmentTransactionKt {
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! add(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, String tag = null, android.os.Bundle? args = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! add(androidx.fragment.app.FragmentTransaction, String tag, android.os.Bundle? args = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! replace(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, String tag = null, android.os.Bundle? args = null);
+ }
+
+ public final class FragmentViewModelLazyKt {
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! activityViewModels(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+ method @MainThread public static <VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> createViewModelLazy(androidx.fragment.app.Fragment, kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+ method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! viewModels(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer = { return this }, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+ }
+
+ public final class ViewKt {
+ method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+ }
+
+}
+
diff --git a/fragment/fragment-testing/api/1.3.0-beta01.txt b/fragment/fragment-testing/api/1.3.0-beta01.txt
new file mode 100644
index 0000000..c3e223b
--- /dev/null
+++ b/fragment/fragment-testing/api/1.3.0-beta01.txt
@@ -0,0 +1,37 @@
+// Signature format: 3.0
+package androidx.fragment.app.testing {
+
+ public final class FragmentScenario<F extends androidx.fragment.app.Fragment> {
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.lifecycle.Lifecycle.State, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.lifecycle.Lifecycle.State, androidx.fragment.app.FragmentFactory?);
+ method public androidx.fragment.app.testing.FragmentScenario<F!> moveToState(androidx.lifecycle.Lifecycle.State);
+ method public androidx.fragment.app.testing.FragmentScenario<F!> onFragment(androidx.fragment.app.testing.FragmentScenario.FragmentAction<F!>);
+ method public androidx.fragment.app.testing.FragmentScenario<F!> recreate();
+ }
+
+ public static interface FragmentScenario.FragmentAction<F extends androidx.fragment.app.Fragment> {
+ method public void perform(F);
+ }
+
+ public final class FragmentScenarioKt {
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.fragment.app.FragmentFactory? factory = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, kotlin.jvm.functions.Function0<? extends F> instantiate);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, androidx.fragment.app.FragmentFactory? factory = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, kotlin.jvm.functions.Function0<? extends F> instantiate);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.fragment.app.FragmentFactory? factory = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, kotlin.jvm.functions.Function0<? extends F> instantiate);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, androidx.fragment.app.FragmentFactory? factory = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, kotlin.jvm.functions.Function0<? extends F> instantiate);
+ method public static inline <reified F extends androidx.fragment.app.Fragment, T> T! withFragment(androidx.fragment.app.testing.FragmentScenario<F>, kotlin.jvm.functions.Function1<? super F,? extends T> block);
+ }
+
+}
+
diff --git a/fragment/fragment-testing/api/public_plus_experimental_1.3.0-beta01.txt b/fragment/fragment-testing/api/public_plus_experimental_1.3.0-beta01.txt
new file mode 100644
index 0000000..c3e223b
--- /dev/null
+++ b/fragment/fragment-testing/api/public_plus_experimental_1.3.0-beta01.txt
@@ -0,0 +1,37 @@
+// Signature format: 3.0
+package androidx.fragment.app.testing {
+
+ public final class FragmentScenario<F extends androidx.fragment.app.Fragment> {
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.lifecycle.Lifecycle.State, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.lifecycle.Lifecycle.State, androidx.fragment.app.FragmentFactory?);
+ method public androidx.fragment.app.testing.FragmentScenario<F!> moveToState(androidx.lifecycle.Lifecycle.State);
+ method public androidx.fragment.app.testing.FragmentScenario<F!> onFragment(androidx.fragment.app.testing.FragmentScenario.FragmentAction<F!>);
+ method public androidx.fragment.app.testing.FragmentScenario<F!> recreate();
+ }
+
+ public static interface FragmentScenario.FragmentAction<F extends androidx.fragment.app.Fragment> {
+ method public void perform(F);
+ }
+
+ public final class FragmentScenarioKt {
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.fragment.app.FragmentFactory? factory = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, kotlin.jvm.functions.Function0<? extends F> instantiate);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, androidx.fragment.app.FragmentFactory? factory = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, kotlin.jvm.functions.Function0<? extends F> instantiate);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.fragment.app.FragmentFactory? factory = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, kotlin.jvm.functions.Function0<? extends F> instantiate);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, androidx.fragment.app.FragmentFactory? factory = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, kotlin.jvm.functions.Function0<? extends F> instantiate);
+ method public static inline <reified F extends androidx.fragment.app.Fragment, T> T! withFragment(androidx.fragment.app.testing.FragmentScenario<F>, kotlin.jvm.functions.Function1<? super F,? extends T> block);
+ }
+
+}
+
diff --git a/fragment/fragment-testing/api/res-1.3.0-beta01.txt b/fragment/fragment-testing/api/res-1.3.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fragment/fragment-testing/api/res-1.3.0-beta01.txt
diff --git a/fragment/fragment-testing/api/restricted_1.3.0-beta01.txt b/fragment/fragment-testing/api/restricted_1.3.0-beta01.txt
new file mode 100644
index 0000000..c3e223b
--- /dev/null
+++ b/fragment/fragment-testing/api/restricted_1.3.0-beta01.txt
@@ -0,0 +1,37 @@
+// Signature format: 3.0
+package androidx.fragment.app.testing {
+
+ public final class FragmentScenario<F extends androidx.fragment.app.Fragment> {
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.lifecycle.Lifecycle.State, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.fragment.app.FragmentFactory?);
+ method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.lifecycle.Lifecycle.State, androidx.fragment.app.FragmentFactory?);
+ method public androidx.fragment.app.testing.FragmentScenario<F!> moveToState(androidx.lifecycle.Lifecycle.State);
+ method public androidx.fragment.app.testing.FragmentScenario<F!> onFragment(androidx.fragment.app.testing.FragmentScenario.FragmentAction<F!>);
+ method public androidx.fragment.app.testing.FragmentScenario<F!> recreate();
+ }
+
+ public static interface FragmentScenario.FragmentAction<F extends androidx.fragment.app.Fragment> {
+ method public void perform(F);
+ }
+
+ public final class FragmentScenarioKt {
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.fragment.app.FragmentFactory? factory = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, kotlin.jvm.functions.Function0<? extends F> instantiate);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, androidx.fragment.app.FragmentFactory? factory = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, kotlin.jvm.functions.Function0<? extends F> instantiate);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.fragment.app.FragmentFactory? factory = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, kotlin.jvm.functions.Function0<? extends F> instantiate);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, androidx.fragment.app.FragmentFactory? factory = null);
+ method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, kotlin.jvm.functions.Function0<? extends F> instantiate);
+ method public static inline <reified F extends androidx.fragment.app.Fragment, T> T! withFragment(androidx.fragment.app.testing.FragmentScenario<F>, kotlin.jvm.functions.Function1<? super F,? extends T> block);
+ }
+
+}
+
diff --git a/fragment/fragment/api/1.3.0-beta01.txt b/fragment/fragment/api/1.3.0-beta01.txt
new file mode 100644
index 0000000..6fd13dc
--- /dev/null
+++ b/fragment/fragment/api/1.3.0-beta01.txt
@@ -0,0 +1,450 @@
+// Signature format: 3.0
+package androidx.fragment.app {
+
+ public class DialogFragment extends androidx.fragment.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+ ctor public DialogFragment();
+ ctor public DialogFragment(@LayoutRes int);
+ method public void dismiss();
+ method public void dismissAllowingStateLoss();
+ method public android.app.Dialog? getDialog();
+ method public boolean getShowsDialog();
+ method @StyleRes public int getTheme();
+ method public boolean isCancelable();
+ method public void onCancel(android.content.DialogInterface);
+ method @MainThread public android.app.Dialog onCreateDialog(android.os.Bundle?);
+ method public void onDismiss(android.content.DialogInterface);
+ method public final android.app.Dialog requireDialog();
+ method public void setCancelable(boolean);
+ method public void setShowsDialog(boolean);
+ method public void setStyle(int, @StyleRes int);
+ method public void show(androidx.fragment.app.FragmentManager, String?);
+ method public int show(androidx.fragment.app.FragmentTransaction, String?);
+ method public void showNow(androidx.fragment.app.FragmentManager, String?);
+ field public static final int STYLE_NORMAL = 0; // 0x0
+ field public static final int STYLE_NO_FRAME = 2; // 0x2
+ field public static final int STYLE_NO_INPUT = 3; // 0x3
+ field public static final int STYLE_NO_TITLE = 1; // 0x1
+ }
+
+ public class Fragment implements androidx.activity.result.ActivityResultCaller android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+ ctor public Fragment();
+ ctor @ContentView public Fragment(@LayoutRes int);
+ method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+ method public final boolean equals(Object?);
+ method public final androidx.fragment.app.FragmentActivity? getActivity();
+ method public boolean getAllowEnterTransitionOverlap();
+ method public boolean getAllowReturnTransitionOverlap();
+ method public final android.os.Bundle? getArguments();
+ method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
+ method public android.content.Context? getContext();
+ method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+ method public Object? getEnterTransition();
+ method public Object? getExitTransition();
+ method @Deprecated public final androidx.fragment.app.FragmentManager? getFragmentManager();
+ method public final Object? getHost();
+ method public final int getId();
+ method public final android.view.LayoutInflater getLayoutInflater();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method @Deprecated public androidx.loader.app.LoaderManager getLoaderManager();
+ method public final androidx.fragment.app.Fragment? getParentFragment();
+ method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
+ method public Object? getReenterTransition();
+ method public final android.content.res.Resources getResources();
+ method @Deprecated public final boolean getRetainInstance();
+ method public Object? getReturnTransition();
+ method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+ method public Object? getSharedElementEnterTransition();
+ method public Object? getSharedElementReturnTransition();
+ method public final String getString(@StringRes int);
+ method public final String getString(@StringRes int, java.lang.Object!...);
+ method public final String? getTag();
+ method @Deprecated public final androidx.fragment.app.Fragment? getTargetFragment();
+ method @Deprecated public final int getTargetRequestCode();
+ method public final CharSequence getText(@StringRes int);
+ method @Deprecated public boolean getUserVisibleHint();
+ method public android.view.View? getView();
+ method @MainThread public androidx.lifecycle.LifecycleOwner getViewLifecycleOwner();
+ method public androidx.lifecycle.LiveData<androidx.lifecycle.LifecycleOwner!> getViewLifecycleOwnerLiveData();
+ method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ method public final int hashCode();
+ method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String);
+ method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+ method public final boolean isAdded();
+ method public final boolean isDetached();
+ method public final boolean isHidden();
+ method public final boolean isInLayout();
+ method public final boolean isRemoving();
+ method public final boolean isResumed();
+ method public final boolean isStateSaved();
+ method public final boolean isVisible();
+ method @Deprecated @CallSuper @MainThread public void onActivityCreated(android.os.Bundle?);
+ method @Deprecated public void onActivityResult(int, int, android.content.Intent?);
+ method @CallSuper @MainThread public void onAttach(android.content.Context);
+ method @Deprecated @CallSuper @MainThread public void onAttach(android.app.Activity);
+ method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+ method @CallSuper public void onConfigurationChanged(android.content.res.Configuration);
+ method @MainThread public boolean onContextItemSelected(android.view.MenuItem);
+ method @CallSuper @MainThread public void onCreate(android.os.Bundle?);
+ method @MainThread public android.view.animation.Animation? onCreateAnimation(int, boolean, int);
+ method @MainThread public android.animation.Animator? onCreateAnimator(int, boolean, int);
+ method @MainThread public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo?);
+ method @MainThread public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+ method @MainThread public android.view.View? onCreateView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
+ method @CallSuper @MainThread public void onDestroy();
+ method @MainThread public void onDestroyOptionsMenu();
+ method @CallSuper @MainThread public void onDestroyView();
+ method @CallSuper @MainThread public void onDetach();
+ method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle?);
+ method @MainThread public void onHiddenChanged(boolean);
+ method @CallSuper @UiThread public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle?);
+ method @Deprecated @CallSuper @UiThread public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle?);
+ method @CallSuper @MainThread public void onLowMemory();
+ method public void onMultiWindowModeChanged(boolean);
+ method @MainThread public boolean onOptionsItemSelected(android.view.MenuItem);
+ method @MainThread public void onOptionsMenuClosed(android.view.Menu);
+ method @CallSuper @MainThread public void onPause();
+ method public void onPictureInPictureModeChanged(boolean);
+ method @MainThread public void onPrepareOptionsMenu(android.view.Menu);
+ method @MainThread public void onPrimaryNavigationFragmentChanged(boolean);
+ method @Deprecated public void onRequestPermissionsResult(int, String![], int[]);
+ method @CallSuper @MainThread public void onResume();
+ method @MainThread public void onSaveInstanceState(android.os.Bundle);
+ method @CallSuper @MainThread public void onStart();
+ method @CallSuper @MainThread public void onStop();
+ method @MainThread public void onViewCreated(android.view.View, android.os.Bundle?);
+ method @CallSuper @MainThread public void onViewStateRestored(android.os.Bundle?);
+ method public void postponeEnterTransition();
+ method public final void postponeEnterTransition(long, java.util.concurrent.TimeUnit);
+ method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+ method public void registerForContextMenu(android.view.View);
+ method @Deprecated public final void requestPermissions(String![], int);
+ method public final androidx.fragment.app.FragmentActivity requireActivity();
+ method public final android.os.Bundle requireArguments();
+ method public final android.content.Context requireContext();
+ method @Deprecated public final androidx.fragment.app.FragmentManager requireFragmentManager();
+ method public final Object requireHost();
+ method public final androidx.fragment.app.Fragment requireParentFragment();
+ method public final android.view.View requireView();
+ method public void setAllowEnterTransitionOverlap(boolean);
+ method public void setAllowReturnTransitionOverlap(boolean);
+ method public void setArguments(android.os.Bundle?);
+ method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+ method public void setEnterTransition(Object?);
+ method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+ method public void setExitTransition(Object?);
+ method public void setHasOptionsMenu(boolean);
+ method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
+ method public void setMenuVisibility(boolean);
+ method public void setReenterTransition(Object?);
+ method @Deprecated public void setRetainInstance(boolean);
+ method public void setReturnTransition(Object?);
+ method public void setSharedElementEnterTransition(Object?);
+ method public void setSharedElementReturnTransition(Object?);
+ method @Deprecated public void setTargetFragment(androidx.fragment.app.Fragment?, int);
+ method @Deprecated public void setUserVisibleHint(boolean);
+ method public boolean shouldShowRequestPermissionRationale(String);
+ method public void startActivity(android.content.Intent!);
+ method public void startActivity(android.content.Intent!, android.os.Bundle?);
+ method @Deprecated public void startActivityForResult(android.content.Intent!, int);
+ method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void startPostponedEnterTransition();
+ method public void unregisterForContextMenu(android.view.View);
+ }
+
+ public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+ ctor public Fragment.InstantiationException(String, Exception?);
+ }
+
+ public static class Fragment.SavedState implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<androidx.fragment.app.Fragment.SavedState!> CREATOR;
+ }
+
+ public class FragmentActivity extends androidx.activity.ComponentActivity implements androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback androidx.lifecycle.LifecycleOwner {
+ ctor public FragmentActivity();
+ ctor @ContentView public FragmentActivity(@LayoutRes int);
+ method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+ method @Deprecated public androidx.loader.app.LoaderManager getSupportLoaderManager();
+ method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+ method @CallSuper public void onMultiWindowModeChanged(boolean);
+ method @CallSuper public void onPictureInPictureModeChanged(boolean);
+ method protected void onResumeFragments();
+ method public void onStateNotSaved();
+ method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+ method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+ method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
+ method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void supportFinishAfterTransition();
+ method @Deprecated public void supportInvalidateOptionsMenu();
+ method public void supportPostponeEnterTransition();
+ method public void supportStartPostponedEnterTransition();
+ method @Deprecated public final void validateRequestPermissionsRequestCode(int);
+ }
+
+ public abstract class FragmentContainer {
+ ctor public FragmentContainer();
+ method @Deprecated public androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+ method public abstract android.view.View? onFindViewById(@IdRes int);
+ method public abstract boolean onHasView();
+ }
+
+ public final class FragmentContainerView extends android.widget.FrameLayout {
+ ctor public FragmentContainerView(android.content.Context);
+ ctor public FragmentContainerView(android.content.Context, android.util.AttributeSet?);
+ ctor public FragmentContainerView(android.content.Context, android.util.AttributeSet?, int);
+ }
+
+ public class FragmentController {
+ method public void attachHost(androidx.fragment.app.Fragment?);
+ method public static androidx.fragment.app.FragmentController createController(androidx.fragment.app.FragmentHostCallback<?>);
+ method public void dispatchActivityCreated();
+ method public void dispatchConfigurationChanged(android.content.res.Configuration);
+ method public boolean dispatchContextItemSelected(android.view.MenuItem);
+ method public void dispatchCreate();
+ method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+ method public void dispatchDestroy();
+ method public void dispatchDestroyView();
+ method public void dispatchLowMemory();
+ method public void dispatchMultiWindowModeChanged(boolean);
+ method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+ method public void dispatchOptionsMenuClosed(android.view.Menu);
+ method public void dispatchPause();
+ method public void dispatchPictureInPictureModeChanged(boolean);
+ method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+ method @Deprecated public void dispatchReallyStop();
+ method public void dispatchResume();
+ method public void dispatchStart();
+ method public void dispatchStop();
+ method @Deprecated public void doLoaderDestroy();
+ method @Deprecated public void doLoaderRetain();
+ method @Deprecated public void doLoaderStart();
+ method @Deprecated public void doLoaderStop(boolean);
+ method @Deprecated public void dumpLoaders(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+ method public boolean execPendingActions();
+ method public androidx.fragment.app.Fragment? findFragmentByWho(String);
+ method public java.util.List<androidx.fragment.app.Fragment!> getActiveFragments(java.util.List<androidx.fragment.app.Fragment!>!);
+ method public int getActiveFragmentsCount();
+ method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+ method @Deprecated public androidx.loader.app.LoaderManager! getSupportLoaderManager();
+ method public void noteStateNotSaved();
+ method public android.view.View? onCreateView(android.view.View?, String, android.content.Context, android.util.AttributeSet);
+ method @Deprecated public void reportLoaderStart();
+ method @Deprecated public void restoreAllState(android.os.Parcelable?, java.util.List<androidx.fragment.app.Fragment!>?);
+ method @Deprecated public void restoreAllState(android.os.Parcelable?, androidx.fragment.app.FragmentManagerNonConfig?);
+ method @Deprecated public void restoreLoaderNonConfig(androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>!);
+ method public void restoreSaveState(android.os.Parcelable?);
+ method @Deprecated public androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>? retainLoaderNonConfig();
+ method @Deprecated public androidx.fragment.app.FragmentManagerNonConfig? retainNestedNonConfig();
+ method @Deprecated public java.util.List<androidx.fragment.app.Fragment!>? retainNonConfig();
+ method public android.os.Parcelable? saveAllState();
+ }
+
+ public class FragmentFactory {
+ ctor public FragmentFactory();
+ method public androidx.fragment.app.Fragment instantiate(ClassLoader, String);
+ method public static Class<? extends androidx.fragment.app.Fragment> loadFragmentClass(ClassLoader, String);
+ }
+
+ public abstract class FragmentHostCallback<E> extends androidx.fragment.app.FragmentContainer {
+ ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+ method public void onDump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+ method public android.view.View? onFindViewById(int);
+ method public abstract E? onGetHost();
+ method public android.view.LayoutInflater onGetLayoutInflater();
+ method public int onGetWindowAnimations();
+ method public boolean onHasView();
+ method public boolean onHasWindowAnimations();
+ method @Deprecated public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, String![], int);
+ method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
+ method public boolean onShouldShowRequestPermissionRationale(String);
+ method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
+ method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
+ method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void onSupportInvalidateOptionsMenu();
+ }
+
+ public abstract class FragmentManager implements androidx.fragment.app.FragmentResultOwner {
+ ctor public FragmentManager();
+ method public void addFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+ method public void addOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+ method public androidx.fragment.app.FragmentTransaction beginTransaction();
+ method public final void clearFragmentResult(String);
+ method public final void clearFragmentResultListener(String);
+ method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+ method @Deprecated public static void enableDebugLogging(boolean);
+ method public boolean executePendingTransactions();
+ method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+ method public androidx.fragment.app.Fragment? findFragmentById(@IdRes int);
+ method public androidx.fragment.app.Fragment? findFragmentByTag(String?);
+ method public androidx.fragment.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+ method public int getBackStackEntryCount();
+ method public androidx.fragment.app.Fragment? getFragment(android.os.Bundle, String);
+ method public androidx.fragment.app.FragmentFactory getFragmentFactory();
+ method public java.util.List<androidx.fragment.app.Fragment!> getFragments();
+ method public androidx.fragment.app.Fragment? getPrimaryNavigationFragment();
+ method public boolean isDestroyed();
+ method public boolean isStateSaved();
+ method public void popBackStack();
+ method public void popBackStack(String?, int);
+ method public void popBackStack(int, int);
+ method public boolean popBackStackImmediate();
+ method public boolean popBackStackImmediate(String?, int);
+ method public boolean popBackStackImmediate(int, int);
+ method public void putFragment(android.os.Bundle, String, androidx.fragment.app.Fragment);
+ method public void registerFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
+ method public void removeFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+ method public void removeOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+ method public androidx.fragment.app.Fragment.SavedState? saveFragmentInstanceState(androidx.fragment.app.Fragment);
+ method public void setFragmentFactory(androidx.fragment.app.FragmentFactory);
+ method public final void setFragmentResult(String, android.os.Bundle);
+ method public final void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+ method public void unregisterFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks);
+ field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+ }
+
+ public static interface FragmentManager.BackStackEntry {
+ method @Deprecated public CharSequence? getBreadCrumbShortTitle();
+ method @Deprecated @StringRes public int getBreadCrumbShortTitleRes();
+ method @Deprecated public CharSequence? getBreadCrumbTitle();
+ method @Deprecated @StringRes public int getBreadCrumbTitleRes();
+ method public int getId();
+ method public String? getName();
+ }
+
+ public abstract static class FragmentManager.FragmentLifecycleCallbacks {
+ ctor public FragmentManager.FragmentLifecycleCallbacks();
+ method @Deprecated public void onFragmentActivityCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+ method public void onFragmentAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+ method public void onFragmentCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+ method public void onFragmentDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentDetached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentPaused(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentPreAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+ method public void onFragmentPreCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+ method public void onFragmentResumed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentSaveInstanceState(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
+ method public void onFragmentStarted(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentStopped(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentViewCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.view.View, android.os.Bundle?);
+ method public void onFragmentViewDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ }
+
+ public static interface FragmentManager.OnBackStackChangedListener {
+ method @MainThread public void onBackStackChanged();
+ }
+
+ @Deprecated public class FragmentManagerNonConfig {
+ }
+
+ public interface FragmentOnAttachListener {
+ method @MainThread public void onAttachFragment(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ }
+
+ @Deprecated public abstract class FragmentPagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+ ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager);
+ ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager, int);
+ method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+ method @Deprecated public long getItemId(int);
+ method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+ field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+ }
+
+ public interface FragmentResultListener {
+ method public void onFragmentResult(String, android.os.Bundle);
+ }
+
+ public interface FragmentResultOwner {
+ method public void clearFragmentResult(String);
+ method public void clearFragmentResultListener(String);
+ method public void setFragmentResult(String, android.os.Bundle);
+ method public void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+ }
+
+ @Deprecated public abstract class FragmentStatePagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+ ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager);
+ ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager, int);
+ method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+ method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+ field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+ }
+
+ @Deprecated public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+ ctor @Deprecated public FragmentTabHost(android.content.Context);
+ ctor @Deprecated public FragmentTabHost(android.content.Context, android.util.AttributeSet?);
+ method @Deprecated public void addTab(android.widget.TabHost.TabSpec, Class<?>, android.os.Bundle?);
+ method @Deprecated public void onTabChanged(String?);
+ method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager);
+ method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager, int);
+ }
+
+ public abstract class FragmentTransaction {
+ ctor @Deprecated public FragmentTransaction();
+ method public final androidx.fragment.app.FragmentTransaction add(Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+ method public androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.Fragment, String?);
+ method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+ method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment);
+ method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+ method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment, String?);
+ method public androidx.fragment.app.FragmentTransaction addSharedElement(android.view.View, String);
+ method public androidx.fragment.app.FragmentTransaction addToBackStack(String?);
+ method public androidx.fragment.app.FragmentTransaction attach(androidx.fragment.app.Fragment);
+ method public abstract int commit();
+ method public abstract int commitAllowingStateLoss();
+ method public abstract void commitNow();
+ method public abstract void commitNowAllowingStateLoss();
+ method public androidx.fragment.app.FragmentTransaction detach(androidx.fragment.app.Fragment);
+ method public androidx.fragment.app.FragmentTransaction disallowAddToBackStack();
+ method public androidx.fragment.app.FragmentTransaction hide(androidx.fragment.app.Fragment);
+ method public boolean isAddToBackStackAllowed();
+ method public boolean isEmpty();
+ method public androidx.fragment.app.FragmentTransaction remove(androidx.fragment.app.Fragment);
+ method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+ method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment);
+ method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+ method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment, String?);
+ method public androidx.fragment.app.FragmentTransaction runOnCommit(Runnable);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setAllowOptimization(boolean);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(@StringRes int);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(CharSequence?);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(@StringRes int);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(CharSequence?);
+ method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+ method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+ method public androidx.fragment.app.FragmentTransaction setMaxLifecycle(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
+ method public androidx.fragment.app.FragmentTransaction setPrimaryNavigationFragment(androidx.fragment.app.Fragment?);
+ method public androidx.fragment.app.FragmentTransaction setReorderingAllowed(boolean);
+ method public androidx.fragment.app.FragmentTransaction setTransition(int);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setTransitionStyle(@StyleRes int);
+ method public androidx.fragment.app.FragmentTransaction show(androidx.fragment.app.Fragment);
+ field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+ field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+ field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+ field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+ field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+ field public static final int TRANSIT_NONE = 0; // 0x0
+ field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+ }
+
+ public class ListFragment extends androidx.fragment.app.Fragment {
+ ctor public ListFragment();
+ method public android.widget.ListAdapter? getListAdapter();
+ method public android.widget.ListView getListView();
+ method public long getSelectedItemId();
+ method public int getSelectedItemPosition();
+ method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+ method public final android.widget.ListAdapter requireListAdapter();
+ method public void setEmptyText(CharSequence?);
+ method public void setListAdapter(android.widget.ListAdapter?);
+ method public void setListShown(boolean);
+ method public void setListShownNoAnimation(boolean);
+ method public void setSelection(int);
+ }
+
+}
+
diff --git a/fragment/fragment/api/public_plus_experimental_1.3.0-beta01.txt b/fragment/fragment/api/public_plus_experimental_1.3.0-beta01.txt
new file mode 100644
index 0000000..7512f13
--- /dev/null
+++ b/fragment/fragment/api/public_plus_experimental_1.3.0-beta01.txt
@@ -0,0 +1,454 @@
+// Signature format: 3.0
+package androidx.fragment.app {
+
+ public class DialogFragment extends androidx.fragment.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+ ctor public DialogFragment();
+ ctor public DialogFragment(@LayoutRes int);
+ method public void dismiss();
+ method public void dismissAllowingStateLoss();
+ method public android.app.Dialog? getDialog();
+ method public boolean getShowsDialog();
+ method @StyleRes public int getTheme();
+ method public boolean isCancelable();
+ method public void onCancel(android.content.DialogInterface);
+ method @MainThread public android.app.Dialog onCreateDialog(android.os.Bundle?);
+ method public void onDismiss(android.content.DialogInterface);
+ method public final android.app.Dialog requireDialog();
+ method public void setCancelable(boolean);
+ method public void setShowsDialog(boolean);
+ method public void setStyle(int, @StyleRes int);
+ method public void show(androidx.fragment.app.FragmentManager, String?);
+ method public int show(androidx.fragment.app.FragmentTransaction, String?);
+ method public void showNow(androidx.fragment.app.FragmentManager, String?);
+ field public static final int STYLE_NORMAL = 0; // 0x0
+ field public static final int STYLE_NO_FRAME = 2; // 0x2
+ field public static final int STYLE_NO_INPUT = 3; // 0x3
+ field public static final int STYLE_NO_TITLE = 1; // 0x1
+ }
+
+ public class Fragment implements androidx.activity.result.ActivityResultCaller android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+ ctor public Fragment();
+ ctor @ContentView public Fragment(@LayoutRes int);
+ method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+ method public final boolean equals(Object?);
+ method public final androidx.fragment.app.FragmentActivity? getActivity();
+ method public boolean getAllowEnterTransitionOverlap();
+ method public boolean getAllowReturnTransitionOverlap();
+ method public final android.os.Bundle? getArguments();
+ method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
+ method public android.content.Context? getContext();
+ method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+ method public Object? getEnterTransition();
+ method public Object? getExitTransition();
+ method @Deprecated public final androidx.fragment.app.FragmentManager? getFragmentManager();
+ method public final Object? getHost();
+ method public final int getId();
+ method public final android.view.LayoutInflater getLayoutInflater();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method @Deprecated public androidx.loader.app.LoaderManager getLoaderManager();
+ method public final androidx.fragment.app.Fragment? getParentFragment();
+ method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
+ method public Object? getReenterTransition();
+ method public final android.content.res.Resources getResources();
+ method @Deprecated public final boolean getRetainInstance();
+ method public Object? getReturnTransition();
+ method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+ method public Object? getSharedElementEnterTransition();
+ method public Object? getSharedElementReturnTransition();
+ method public final String getString(@StringRes int);
+ method public final String getString(@StringRes int, java.lang.Object!...);
+ method public final String? getTag();
+ method @Deprecated public final androidx.fragment.app.Fragment? getTargetFragment();
+ method @Deprecated public final int getTargetRequestCode();
+ method public final CharSequence getText(@StringRes int);
+ method @Deprecated public boolean getUserVisibleHint();
+ method public android.view.View? getView();
+ method @MainThread public androidx.lifecycle.LifecycleOwner getViewLifecycleOwner();
+ method public androidx.lifecycle.LiveData<androidx.lifecycle.LifecycleOwner!> getViewLifecycleOwnerLiveData();
+ method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ method public final int hashCode();
+ method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String);
+ method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+ method public final boolean isAdded();
+ method public final boolean isDetached();
+ method public final boolean isHidden();
+ method public final boolean isInLayout();
+ method public final boolean isRemoving();
+ method public final boolean isResumed();
+ method public final boolean isStateSaved();
+ method public final boolean isVisible();
+ method @Deprecated @CallSuper @MainThread public void onActivityCreated(android.os.Bundle?);
+ method @Deprecated public void onActivityResult(int, int, android.content.Intent?);
+ method @CallSuper @MainThread public void onAttach(android.content.Context);
+ method @Deprecated @CallSuper @MainThread public void onAttach(android.app.Activity);
+ method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+ method @CallSuper public void onConfigurationChanged(android.content.res.Configuration);
+ method @MainThread public boolean onContextItemSelected(android.view.MenuItem);
+ method @CallSuper @MainThread public void onCreate(android.os.Bundle?);
+ method @MainThread public android.view.animation.Animation? onCreateAnimation(int, boolean, int);
+ method @MainThread public android.animation.Animator? onCreateAnimator(int, boolean, int);
+ method @MainThread public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo?);
+ method @MainThread public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+ method @MainThread public android.view.View? onCreateView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
+ method @CallSuper @MainThread public void onDestroy();
+ method @MainThread public void onDestroyOptionsMenu();
+ method @CallSuper @MainThread public void onDestroyView();
+ method @CallSuper @MainThread public void onDetach();
+ method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle?);
+ method @MainThread public void onHiddenChanged(boolean);
+ method @CallSuper @UiThread public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle?);
+ method @Deprecated @CallSuper @UiThread public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle?);
+ method @CallSuper @MainThread public void onLowMemory();
+ method public void onMultiWindowModeChanged(boolean);
+ method @MainThread public boolean onOptionsItemSelected(android.view.MenuItem);
+ method @MainThread public void onOptionsMenuClosed(android.view.Menu);
+ method @CallSuper @MainThread public void onPause();
+ method public void onPictureInPictureModeChanged(boolean);
+ method @MainThread public void onPrepareOptionsMenu(android.view.Menu);
+ method @MainThread public void onPrimaryNavigationFragmentChanged(boolean);
+ method @Deprecated public void onRequestPermissionsResult(int, String![], int[]);
+ method @CallSuper @MainThread public void onResume();
+ method @MainThread public void onSaveInstanceState(android.os.Bundle);
+ method @CallSuper @MainThread public void onStart();
+ method @CallSuper @MainThread public void onStop();
+ method @MainThread public void onViewCreated(android.view.View, android.os.Bundle?);
+ method @CallSuper @MainThread public void onViewStateRestored(android.os.Bundle?);
+ method public void postponeEnterTransition();
+ method public final void postponeEnterTransition(long, java.util.concurrent.TimeUnit);
+ method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+ method public void registerForContextMenu(android.view.View);
+ method @Deprecated public final void requestPermissions(String![], int);
+ method public final androidx.fragment.app.FragmentActivity requireActivity();
+ method public final android.os.Bundle requireArguments();
+ method public final android.content.Context requireContext();
+ method @Deprecated public final androidx.fragment.app.FragmentManager requireFragmentManager();
+ method public final Object requireHost();
+ method public final androidx.fragment.app.Fragment requireParentFragment();
+ method public final android.view.View requireView();
+ method public void setAllowEnterTransitionOverlap(boolean);
+ method public void setAllowReturnTransitionOverlap(boolean);
+ method public void setArguments(android.os.Bundle?);
+ method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+ method public void setEnterTransition(Object?);
+ method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+ method public void setExitTransition(Object?);
+ method public void setHasOptionsMenu(boolean);
+ method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
+ method public void setMenuVisibility(boolean);
+ method public void setReenterTransition(Object?);
+ method @Deprecated public void setRetainInstance(boolean);
+ method public void setReturnTransition(Object?);
+ method public void setSharedElementEnterTransition(Object?);
+ method public void setSharedElementReturnTransition(Object?);
+ method @Deprecated public void setTargetFragment(androidx.fragment.app.Fragment?, int);
+ method @Deprecated public void setUserVisibleHint(boolean);
+ method public boolean shouldShowRequestPermissionRationale(String);
+ method public void startActivity(android.content.Intent!);
+ method public void startActivity(android.content.Intent!, android.os.Bundle?);
+ method @Deprecated public void startActivityForResult(android.content.Intent!, int);
+ method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void startPostponedEnterTransition();
+ method public void unregisterForContextMenu(android.view.View);
+ }
+
+ public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+ ctor public Fragment.InstantiationException(String, Exception?);
+ }
+
+ public static class Fragment.SavedState implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<androidx.fragment.app.Fragment.SavedState!> CREATOR;
+ }
+
+ public class FragmentActivity extends androidx.activity.ComponentActivity implements androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback androidx.core.app.ActivityCompat.RequestPermissionsRequestCodeValidator {
+ ctor public FragmentActivity();
+ ctor @ContentView public FragmentActivity(@LayoutRes int);
+ method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+ method @Deprecated public androidx.loader.app.LoaderManager getSupportLoaderManager();
+ method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+ method @CallSuper public void onMultiWindowModeChanged(boolean);
+ method @CallSuper public void onPictureInPictureModeChanged(boolean);
+ method protected void onResumeFragments();
+ method public void onStateNotSaved();
+ method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+ method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+ method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
+ method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void supportFinishAfterTransition();
+ method @Deprecated public void supportInvalidateOptionsMenu();
+ method public void supportPostponeEnterTransition();
+ method public void supportStartPostponedEnterTransition();
+ method @Deprecated public final void validateRequestPermissionsRequestCode(int);
+ }
+
+ public abstract class FragmentContainer {
+ ctor public FragmentContainer();
+ method @Deprecated public androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+ method public abstract android.view.View? onFindViewById(@IdRes int);
+ method public abstract boolean onHasView();
+ }
+
+ public final class FragmentContainerView extends android.widget.FrameLayout {
+ ctor public FragmentContainerView(android.content.Context);
+ ctor public FragmentContainerView(android.content.Context, android.util.AttributeSet?);
+ ctor public FragmentContainerView(android.content.Context, android.util.AttributeSet?, int);
+ }
+
+ public class FragmentController {
+ method public void attachHost(androidx.fragment.app.Fragment?);
+ method public static androidx.fragment.app.FragmentController createController(androidx.fragment.app.FragmentHostCallback<?>);
+ method public void dispatchActivityCreated();
+ method public void dispatchConfigurationChanged(android.content.res.Configuration);
+ method public boolean dispatchContextItemSelected(android.view.MenuItem);
+ method public void dispatchCreate();
+ method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+ method public void dispatchDestroy();
+ method public void dispatchDestroyView();
+ method public void dispatchLowMemory();
+ method public void dispatchMultiWindowModeChanged(boolean);
+ method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+ method public void dispatchOptionsMenuClosed(android.view.Menu);
+ method public void dispatchPause();
+ method public void dispatchPictureInPictureModeChanged(boolean);
+ method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+ method @Deprecated public void dispatchReallyStop();
+ method public void dispatchResume();
+ method public void dispatchStart();
+ method public void dispatchStop();
+ method @Deprecated public void doLoaderDestroy();
+ method @Deprecated public void doLoaderRetain();
+ method @Deprecated public void doLoaderStart();
+ method @Deprecated public void doLoaderStop(boolean);
+ method @Deprecated public void dumpLoaders(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+ method public boolean execPendingActions();
+ method public androidx.fragment.app.Fragment? findFragmentByWho(String);
+ method public java.util.List<androidx.fragment.app.Fragment!> getActiveFragments(java.util.List<androidx.fragment.app.Fragment!>!);
+ method public int getActiveFragmentsCount();
+ method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+ method @Deprecated public androidx.loader.app.LoaderManager! getSupportLoaderManager();
+ method public void noteStateNotSaved();
+ method public android.view.View? onCreateView(android.view.View?, String, android.content.Context, android.util.AttributeSet);
+ method @Deprecated public void reportLoaderStart();
+ method @Deprecated public void restoreAllState(android.os.Parcelable?, java.util.List<androidx.fragment.app.Fragment!>?);
+ method @Deprecated public void restoreAllState(android.os.Parcelable?, androidx.fragment.app.FragmentManagerNonConfig?);
+ method @Deprecated public void restoreLoaderNonConfig(androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>!);
+ method public void restoreSaveState(android.os.Parcelable?);
+ method @Deprecated public androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>? retainLoaderNonConfig();
+ method @Deprecated public androidx.fragment.app.FragmentManagerNonConfig? retainNestedNonConfig();
+ method @Deprecated public java.util.List<androidx.fragment.app.Fragment!>? retainNonConfig();
+ method public android.os.Parcelable? saveAllState();
+ }
+
+ public class FragmentFactory {
+ ctor public FragmentFactory();
+ method public androidx.fragment.app.Fragment instantiate(ClassLoader, String);
+ method public static Class<? extends androidx.fragment.app.Fragment> loadFragmentClass(ClassLoader, String);
+ }
+
+ public abstract class FragmentHostCallback<E> extends androidx.fragment.app.FragmentContainer {
+ ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+ method public void onDump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+ method public android.view.View? onFindViewById(int);
+ method public abstract E? onGetHost();
+ method public android.view.LayoutInflater onGetLayoutInflater();
+ method public int onGetWindowAnimations();
+ method public boolean onHasView();
+ method public boolean onHasWindowAnimations();
+ method @Deprecated public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, String![], int);
+ method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
+ method public boolean onShouldShowRequestPermissionRationale(String);
+ method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
+ method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
+ method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void onSupportInvalidateOptionsMenu();
+ }
+
+ public abstract class FragmentManager implements androidx.fragment.app.FragmentResultOwner {
+ ctor public FragmentManager();
+ method public void addFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+ method public void addOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+ method public androidx.fragment.app.FragmentTransaction beginTransaction();
+ method public final void clearFragmentResult(String);
+ method public final void clearFragmentResultListener(String);
+ method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+ method @Deprecated public static void enableDebugLogging(boolean);
+ method @androidx.fragment.app.FragmentStateManagerControl public static void enableNewStateManager(boolean);
+ method public boolean executePendingTransactions();
+ method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+ method public androidx.fragment.app.Fragment? findFragmentById(@IdRes int);
+ method public androidx.fragment.app.Fragment? findFragmentByTag(String?);
+ method public androidx.fragment.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+ method public int getBackStackEntryCount();
+ method public androidx.fragment.app.Fragment? getFragment(android.os.Bundle, String);
+ method public androidx.fragment.app.FragmentFactory getFragmentFactory();
+ method public java.util.List<androidx.fragment.app.Fragment!> getFragments();
+ method public androidx.fragment.app.Fragment? getPrimaryNavigationFragment();
+ method public boolean isDestroyed();
+ method public boolean isStateSaved();
+ method public void popBackStack();
+ method public void popBackStack(String?, int);
+ method public void popBackStack(int, int);
+ method public boolean popBackStackImmediate();
+ method public boolean popBackStackImmediate(String?, int);
+ method public boolean popBackStackImmediate(int, int);
+ method public void putFragment(android.os.Bundle, String, androidx.fragment.app.Fragment);
+ method public void registerFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
+ method public void removeFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+ method public void removeOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+ method public androidx.fragment.app.Fragment.SavedState? saveFragmentInstanceState(androidx.fragment.app.Fragment);
+ method public void setFragmentFactory(androidx.fragment.app.FragmentFactory);
+ method public final void setFragmentResult(String, android.os.Bundle);
+ method public final void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+ method public void unregisterFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks);
+ field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+ }
+
+ public static interface FragmentManager.BackStackEntry {
+ method @Deprecated public CharSequence? getBreadCrumbShortTitle();
+ method @Deprecated @StringRes public int getBreadCrumbShortTitleRes();
+ method @Deprecated public CharSequence? getBreadCrumbTitle();
+ method @Deprecated @StringRes public int getBreadCrumbTitleRes();
+ method public int getId();
+ method public String? getName();
+ }
+
+ public abstract static class FragmentManager.FragmentLifecycleCallbacks {
+ ctor public FragmentManager.FragmentLifecycleCallbacks();
+ method @Deprecated public void onFragmentActivityCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+ method public void onFragmentAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+ method public void onFragmentCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+ method public void onFragmentDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentDetached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentPaused(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentPreAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+ method public void onFragmentPreCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+ method public void onFragmentResumed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentSaveInstanceState(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
+ method public void onFragmentStarted(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentStopped(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentViewCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.view.View, android.os.Bundle?);
+ method public void onFragmentViewDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ }
+
+ public static interface FragmentManager.OnBackStackChangedListener {
+ method @MainThread public void onBackStackChanged();
+ }
+
+ @Deprecated public class FragmentManagerNonConfig {
+ }
+
+ public interface FragmentOnAttachListener {
+ method @MainThread public void onAttachFragment(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ }
+
+ @Deprecated public abstract class FragmentPagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+ ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager);
+ ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager, int);
+ method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+ method @Deprecated public long getItemId(int);
+ method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+ field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+ }
+
+ public interface FragmentResultListener {
+ method public void onFragmentResult(String, android.os.Bundle);
+ }
+
+ public interface FragmentResultOwner {
+ method public void clearFragmentResult(String);
+ method public void clearFragmentResultListener(String);
+ method public void setFragmentResult(String, android.os.Bundle);
+ method public void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+ }
+
+ @experimental.Experimental(level=androidx.annotation.experimental.Experimental.Level.WARNING) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface FragmentStateManagerControl {
+ }
+
+ @Deprecated public abstract class FragmentStatePagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+ ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager);
+ ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager, int);
+ method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+ method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+ field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+ }
+
+ @Deprecated public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+ ctor @Deprecated public FragmentTabHost(android.content.Context);
+ ctor @Deprecated public FragmentTabHost(android.content.Context, android.util.AttributeSet?);
+ method @Deprecated public void addTab(android.widget.TabHost.TabSpec, Class<?>, android.os.Bundle?);
+ method @Deprecated public void onTabChanged(String?);
+ method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager);
+ method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager, int);
+ }
+
+ public abstract class FragmentTransaction {
+ ctor @Deprecated public FragmentTransaction();
+ method public final androidx.fragment.app.FragmentTransaction add(Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+ method public androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.Fragment, String?);
+ method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+ method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment);
+ method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+ method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment, String?);
+ method public androidx.fragment.app.FragmentTransaction addSharedElement(android.view.View, String);
+ method public androidx.fragment.app.FragmentTransaction addToBackStack(String?);
+ method public androidx.fragment.app.FragmentTransaction attach(androidx.fragment.app.Fragment);
+ method public abstract int commit();
+ method public abstract int commitAllowingStateLoss();
+ method public abstract void commitNow();
+ method public abstract void commitNowAllowingStateLoss();
+ method public androidx.fragment.app.FragmentTransaction detach(androidx.fragment.app.Fragment);
+ method public androidx.fragment.app.FragmentTransaction disallowAddToBackStack();
+ method public androidx.fragment.app.FragmentTransaction hide(androidx.fragment.app.Fragment);
+ method public boolean isAddToBackStackAllowed();
+ method public boolean isEmpty();
+ method public androidx.fragment.app.FragmentTransaction remove(androidx.fragment.app.Fragment);
+ method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+ method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment);
+ method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+ method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment, String?);
+ method public androidx.fragment.app.FragmentTransaction runOnCommit(Runnable);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setAllowOptimization(boolean);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(@StringRes int);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(CharSequence?);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(@StringRes int);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(CharSequence?);
+ method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+ method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+ method public androidx.fragment.app.FragmentTransaction setMaxLifecycle(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
+ method public androidx.fragment.app.FragmentTransaction setPrimaryNavigationFragment(androidx.fragment.app.Fragment?);
+ method public androidx.fragment.app.FragmentTransaction setReorderingAllowed(boolean);
+ method public androidx.fragment.app.FragmentTransaction setTransition(int);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setTransitionStyle(@StyleRes int);
+ method public androidx.fragment.app.FragmentTransaction show(androidx.fragment.app.Fragment);
+ field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+ field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+ field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+ field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+ field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+ field public static final int TRANSIT_NONE = 0; // 0x0
+ field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+ }
+
+ public class ListFragment extends androidx.fragment.app.Fragment {
+ ctor public ListFragment();
+ method public android.widget.ListAdapter? getListAdapter();
+ method public android.widget.ListView getListView();
+ method public long getSelectedItemId();
+ method public int getSelectedItemPosition();
+ method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+ method public final android.widget.ListAdapter requireListAdapter();
+ method public void setEmptyText(CharSequence?);
+ method public void setListAdapter(android.widget.ListAdapter?);
+ method public void setListShown(boolean);
+ method public void setListShownNoAnimation(boolean);
+ method public void setSelection(int);
+ }
+
+}
+
diff --git a/fragment/fragment/api/res-1.3.0-beta01.txt b/fragment/fragment/api/res-1.3.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fragment/fragment/api/res-1.3.0-beta01.txt
diff --git a/fragment/fragment/api/restricted_1.3.0-beta01.txt b/fragment/fragment/api/restricted_1.3.0-beta01.txt
new file mode 100644
index 0000000..a2689d8
--- /dev/null
+++ b/fragment/fragment/api/restricted_1.3.0-beta01.txt
@@ -0,0 +1,480 @@
+// Signature format: 3.0
+package androidx.fragment.app {
+
+ public class DialogFragment extends androidx.fragment.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+ ctor public DialogFragment();
+ ctor public DialogFragment(@LayoutRes int);
+ method public void dismiss();
+ method public void dismissAllowingStateLoss();
+ method public android.app.Dialog? getDialog();
+ method public boolean getShowsDialog();
+ method @StyleRes public int getTheme();
+ method public boolean isCancelable();
+ method public void onCancel(android.content.DialogInterface);
+ method @MainThread public android.app.Dialog onCreateDialog(android.os.Bundle?);
+ method public void onDismiss(android.content.DialogInterface);
+ method public final android.app.Dialog requireDialog();
+ method public void setCancelable(boolean);
+ method public void setShowsDialog(boolean);
+ method public void setStyle(int, @StyleRes int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setupDialog(android.app.Dialog, int);
+ method public void show(androidx.fragment.app.FragmentManager, String?);
+ method public int show(androidx.fragment.app.FragmentTransaction, String?);
+ method public void showNow(androidx.fragment.app.FragmentManager, String?);
+ field public static final int STYLE_NORMAL = 0; // 0x0
+ field public static final int STYLE_NO_FRAME = 2; // 0x2
+ field public static final int STYLE_NO_INPUT = 3; // 0x3
+ field public static final int STYLE_NO_TITLE = 1; // 0x1
+ }
+
+ public class Fragment implements androidx.activity.result.ActivityResultCaller android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+ ctor public Fragment();
+ ctor @ContentView public Fragment(@LayoutRes int);
+ method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+ method public final boolean equals(Object?);
+ method public final androidx.fragment.app.FragmentActivity? getActivity();
+ method public boolean getAllowEnterTransitionOverlap();
+ method public boolean getAllowReturnTransitionOverlap();
+ method public final android.os.Bundle? getArguments();
+ method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
+ method public android.content.Context? getContext();
+ method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+ method public Object? getEnterTransition();
+ method public Object? getExitTransition();
+ method @Deprecated public final androidx.fragment.app.FragmentManager? getFragmentManager();
+ method public final Object? getHost();
+ method public final int getId();
+ method public final android.view.LayoutInflater getLayoutInflater();
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.view.LayoutInflater getLayoutInflater(android.os.Bundle?);
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method @Deprecated public androidx.loader.app.LoaderManager getLoaderManager();
+ method public final androidx.fragment.app.Fragment? getParentFragment();
+ method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
+ method public Object? getReenterTransition();
+ method public final android.content.res.Resources getResources();
+ method @Deprecated public final boolean getRetainInstance();
+ method public Object? getReturnTransition();
+ method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+ method public Object? getSharedElementEnterTransition();
+ method public Object? getSharedElementReturnTransition();
+ method public final String getString(@StringRes int);
+ method public final String getString(@StringRes int, java.lang.Object!...);
+ method public final String? getTag();
+ method @Deprecated public final androidx.fragment.app.Fragment? getTargetFragment();
+ method @Deprecated public final int getTargetRequestCode();
+ method public final CharSequence getText(@StringRes int);
+ method @Deprecated public boolean getUserVisibleHint();
+ method public android.view.View? getView();
+ method @MainThread public androidx.lifecycle.LifecycleOwner getViewLifecycleOwner();
+ method public androidx.lifecycle.LiveData<androidx.lifecycle.LifecycleOwner!> getViewLifecycleOwnerLiveData();
+ method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final boolean hasOptionsMenu();
+ method public final int hashCode();
+ method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String);
+ method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+ method public final boolean isAdded();
+ method public final boolean isDetached();
+ method public final boolean isHidden();
+ method public final boolean isInLayout();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final boolean isMenuVisible();
+ method public final boolean isRemoving();
+ method public final boolean isResumed();
+ method public final boolean isStateSaved();
+ method public final boolean isVisible();
+ method @Deprecated @CallSuper @MainThread public void onActivityCreated(android.os.Bundle?);
+ method @Deprecated public void onActivityResult(int, int, android.content.Intent?);
+ method @CallSuper @MainThread public void onAttach(android.content.Context);
+ method @Deprecated @CallSuper @MainThread public void onAttach(android.app.Activity);
+ method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+ method @CallSuper public void onConfigurationChanged(android.content.res.Configuration);
+ method @MainThread public boolean onContextItemSelected(android.view.MenuItem);
+ method @CallSuper @MainThread public void onCreate(android.os.Bundle?);
+ method @MainThread public android.view.animation.Animation? onCreateAnimation(int, boolean, int);
+ method @MainThread public android.animation.Animator? onCreateAnimator(int, boolean, int);
+ method @MainThread public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo?);
+ method @MainThread public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+ method @MainThread public android.view.View? onCreateView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
+ method @CallSuper @MainThread public void onDestroy();
+ method @MainThread public void onDestroyOptionsMenu();
+ method @CallSuper @MainThread public void onDestroyView();
+ method @CallSuper @MainThread public void onDetach();
+ method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle?);
+ method @MainThread public void onHiddenChanged(boolean);
+ method @CallSuper @UiThread public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle?);
+ method @Deprecated @CallSuper @UiThread public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle?);
+ method @CallSuper @MainThread public void onLowMemory();
+ method public void onMultiWindowModeChanged(boolean);
+ method @MainThread public boolean onOptionsItemSelected(android.view.MenuItem);
+ method @MainThread public void onOptionsMenuClosed(android.view.Menu);
+ method @CallSuper @MainThread public void onPause();
+ method public void onPictureInPictureModeChanged(boolean);
+ method @MainThread public void onPrepareOptionsMenu(android.view.Menu);
+ method @MainThread public void onPrimaryNavigationFragmentChanged(boolean);
+ method @Deprecated public void onRequestPermissionsResult(int, String![], int[]);
+ method @CallSuper @MainThread public void onResume();
+ method @MainThread public void onSaveInstanceState(android.os.Bundle);
+ method @CallSuper @MainThread public void onStart();
+ method @CallSuper @MainThread public void onStop();
+ method @MainThread public void onViewCreated(android.view.View, android.os.Bundle?);
+ method @CallSuper @MainThread public void onViewStateRestored(android.os.Bundle?);
+ method public void postponeEnterTransition();
+ method public final void postponeEnterTransition(long, java.util.concurrent.TimeUnit);
+ method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+ method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+ method public void registerForContextMenu(android.view.View);
+ method @Deprecated public final void requestPermissions(String![], int);
+ method public final androidx.fragment.app.FragmentActivity requireActivity();
+ method public final android.os.Bundle requireArguments();
+ method public final android.content.Context requireContext();
+ method @Deprecated public final androidx.fragment.app.FragmentManager requireFragmentManager();
+ method public final Object requireHost();
+ method public final androidx.fragment.app.Fragment requireParentFragment();
+ method public final android.view.View requireView();
+ method public void setAllowEnterTransitionOverlap(boolean);
+ method public void setAllowReturnTransitionOverlap(boolean);
+ method public void setArguments(android.os.Bundle?);
+ method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+ method public void setEnterTransition(Object?);
+ method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+ method public void setExitTransition(Object?);
+ method public void setHasOptionsMenu(boolean);
+ method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
+ method public void setMenuVisibility(boolean);
+ method public void setReenterTransition(Object?);
+ method @Deprecated public void setRetainInstance(boolean);
+ method public void setReturnTransition(Object?);
+ method public void setSharedElementEnterTransition(Object?);
+ method public void setSharedElementReturnTransition(Object?);
+ method @Deprecated public void setTargetFragment(androidx.fragment.app.Fragment?, int);
+ method @Deprecated public void setUserVisibleHint(boolean);
+ method public boolean shouldShowRequestPermissionRationale(String);
+ method public void startActivity(android.content.Intent!);
+ method public void startActivity(android.content.Intent!, android.os.Bundle?);
+ method @Deprecated public void startActivityForResult(android.content.Intent!, int);
+ method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void startPostponedEnterTransition();
+ method public void unregisterForContextMenu(android.view.View);
+ }
+
+ public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+ ctor public Fragment.InstantiationException(String, Exception?);
+ }
+
+ public static class Fragment.SavedState implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<androidx.fragment.app.Fragment.SavedState!> CREATOR;
+ }
+
+ public class FragmentActivity extends androidx.activity.ComponentActivity implements androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback androidx.core.app.ActivityCompat.RequestPermissionsRequestCodeValidator {
+ ctor public FragmentActivity();
+ ctor @ContentView public FragmentActivity(@LayoutRes int);
+ method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+ method @Deprecated public androidx.loader.app.LoaderManager getSupportLoaderManager();
+ method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+ method @CallSuper public void onMultiWindowModeChanged(boolean);
+ method @CallSuper public void onPictureInPictureModeChanged(boolean);
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected boolean onPrepareOptionsPanel(android.view.View?, android.view.Menu);
+ method protected void onResumeFragments();
+ method public void onStateNotSaved();
+ method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+ method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+ method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
+ method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void supportFinishAfterTransition();
+ method @Deprecated public void supportInvalidateOptionsMenu();
+ method public void supportPostponeEnterTransition();
+ method public void supportStartPostponedEnterTransition();
+ method @Deprecated public final void validateRequestPermissionsRequestCode(int);
+ }
+
+ public abstract class FragmentContainer {
+ ctor public FragmentContainer();
+ method @Deprecated public androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+ method public abstract android.view.View? onFindViewById(@IdRes int);
+ method public abstract boolean onHasView();
+ }
+
+ public final class FragmentContainerView extends android.widget.FrameLayout {
+ ctor public FragmentContainerView(android.content.Context);
+ ctor public FragmentContainerView(android.content.Context, android.util.AttributeSet?);
+ ctor public FragmentContainerView(android.content.Context, android.util.AttributeSet?, int);
+ }
+
+ public class FragmentController {
+ method public void attachHost(androidx.fragment.app.Fragment?);
+ method public static androidx.fragment.app.FragmentController createController(androidx.fragment.app.FragmentHostCallback<?>);
+ method public void dispatchActivityCreated();
+ method public void dispatchConfigurationChanged(android.content.res.Configuration);
+ method public boolean dispatchContextItemSelected(android.view.MenuItem);
+ method public void dispatchCreate();
+ method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+ method public void dispatchDestroy();
+ method public void dispatchDestroyView();
+ method public void dispatchLowMemory();
+ method public void dispatchMultiWindowModeChanged(boolean);
+ method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+ method public void dispatchOptionsMenuClosed(android.view.Menu);
+ method public void dispatchPause();
+ method public void dispatchPictureInPictureModeChanged(boolean);
+ method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+ method @Deprecated public void dispatchReallyStop();
+ method public void dispatchResume();
+ method public void dispatchStart();
+ method public void dispatchStop();
+ method @Deprecated public void doLoaderDestroy();
+ method @Deprecated public void doLoaderRetain();
+ method @Deprecated public void doLoaderStart();
+ method @Deprecated public void doLoaderStop(boolean);
+ method @Deprecated public void dumpLoaders(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+ method public boolean execPendingActions();
+ method public androidx.fragment.app.Fragment? findFragmentByWho(String);
+ method public java.util.List<androidx.fragment.app.Fragment!> getActiveFragments(java.util.List<androidx.fragment.app.Fragment!>!);
+ method public int getActiveFragmentsCount();
+ method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+ method @Deprecated public androidx.loader.app.LoaderManager! getSupportLoaderManager();
+ method public void noteStateNotSaved();
+ method public android.view.View? onCreateView(android.view.View?, String, android.content.Context, android.util.AttributeSet);
+ method @Deprecated public void reportLoaderStart();
+ method @Deprecated public void restoreAllState(android.os.Parcelable?, java.util.List<androidx.fragment.app.Fragment!>?);
+ method @Deprecated public void restoreAllState(android.os.Parcelable?, androidx.fragment.app.FragmentManagerNonConfig?);
+ method @Deprecated public void restoreLoaderNonConfig(androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>!);
+ method public void restoreSaveState(android.os.Parcelable?);
+ method @Deprecated public androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>? retainLoaderNonConfig();
+ method @Deprecated public androidx.fragment.app.FragmentManagerNonConfig? retainNestedNonConfig();
+ method @Deprecated public java.util.List<androidx.fragment.app.Fragment!>? retainNonConfig();
+ method public android.os.Parcelable? saveAllState();
+ }
+
+ public class FragmentFactory {
+ ctor public FragmentFactory();
+ method public androidx.fragment.app.Fragment instantiate(ClassLoader, String);
+ method public static Class<? extends androidx.fragment.app.Fragment> loadFragmentClass(ClassLoader, String);
+ }
+
+ public abstract class FragmentHostCallback<E> extends androidx.fragment.app.FragmentContainer {
+ ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+ method public void onDump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+ method public android.view.View? onFindViewById(int);
+ method public abstract E? onGetHost();
+ method public android.view.LayoutInflater onGetLayoutInflater();
+ method public int onGetWindowAnimations();
+ method public boolean onHasView();
+ method public boolean onHasWindowAnimations();
+ method @Deprecated public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, String![], int);
+ method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
+ method public boolean onShouldShowRequestPermissionRationale(String);
+ method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
+ method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
+ method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void onSupportInvalidateOptionsMenu();
+ }
+
+ public abstract class FragmentManager implements androidx.fragment.app.FragmentResultOwner {
+ ctor public FragmentManager();
+ method public void addFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+ method public void addOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+ method public androidx.fragment.app.FragmentTransaction beginTransaction();
+ method public final void clearFragmentResult(String);
+ method public final void clearFragmentResultListener(String);
+ method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+ method @Deprecated public static void enableDebugLogging(boolean);
+ method public boolean executePendingTransactions();
+ method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+ method public androidx.fragment.app.Fragment? findFragmentById(@IdRes int);
+ method public androidx.fragment.app.Fragment? findFragmentByTag(String?);
+ method public androidx.fragment.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+ method public int getBackStackEntryCount();
+ method public androidx.fragment.app.Fragment? getFragment(android.os.Bundle, String);
+ method public androidx.fragment.app.FragmentFactory getFragmentFactory();
+ method public java.util.List<androidx.fragment.app.Fragment!> getFragments();
+ method public androidx.fragment.app.Fragment? getPrimaryNavigationFragment();
+ method public boolean isDestroyed();
+ method public boolean isStateSaved();
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.fragment.app.FragmentTransaction openTransaction();
+ method public void popBackStack();
+ method public void popBackStack(String?, int);
+ method public void popBackStack(int, int);
+ method public boolean popBackStackImmediate();
+ method public boolean popBackStackImmediate(String?, int);
+ method public boolean popBackStackImmediate(int, int);
+ method public void putFragment(android.os.Bundle, String, androidx.fragment.app.Fragment);
+ method public void registerFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
+ method public void removeFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+ method public void removeOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+ method public androidx.fragment.app.Fragment.SavedState? saveFragmentInstanceState(androidx.fragment.app.Fragment);
+ method public void setFragmentFactory(androidx.fragment.app.FragmentFactory);
+ method public final void setFragmentResult(String, android.os.Bundle);
+ method public final void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+ method public void unregisterFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks);
+ field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+ }
+
+ public static interface FragmentManager.BackStackEntry {
+ method @Deprecated public CharSequence? getBreadCrumbShortTitle();
+ method @Deprecated @StringRes public int getBreadCrumbShortTitleRes();
+ method @Deprecated public CharSequence? getBreadCrumbTitle();
+ method @Deprecated @StringRes public int getBreadCrumbTitleRes();
+ method public int getId();
+ method public String? getName();
+ }
+
+ public abstract static class FragmentManager.FragmentLifecycleCallbacks {
+ ctor public FragmentManager.FragmentLifecycleCallbacks();
+ method @Deprecated public void onFragmentActivityCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+ method public void onFragmentAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+ method public void onFragmentCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+ method public void onFragmentDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentDetached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentPaused(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentPreAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+ method public void onFragmentPreCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+ method public void onFragmentResumed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentSaveInstanceState(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
+ method public void onFragmentStarted(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentStopped(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ method public void onFragmentViewCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.view.View, android.os.Bundle?);
+ method public void onFragmentViewDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ }
+
+ public static interface FragmentManager.OnBackStackChangedListener {
+ method @MainThread public void onBackStackChanged();
+ }
+
+ @Deprecated public class FragmentManagerNonConfig {
+ }
+
+ public interface FragmentOnAttachListener {
+ method @MainThread public void onAttachFragment(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+ }
+
+ @Deprecated public abstract class FragmentPagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+ ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager);
+ ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager, int);
+ method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+ method @Deprecated public long getItemId(int);
+ method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+ field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+ }
+
+ public interface FragmentResultListener {
+ method public void onFragmentResult(String, android.os.Bundle);
+ }
+
+ public interface FragmentResultOwner {
+ method public void clearFragmentResult(String);
+ method public void clearFragmentResultListener(String);
+ method public void setFragmentResult(String, android.os.Bundle);
+ method public void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+ }
+
+ @Deprecated public abstract class FragmentStatePagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+ ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager);
+ ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager, int);
+ method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+ method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+ field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+ }
+
+ @Deprecated public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+ ctor @Deprecated public FragmentTabHost(android.content.Context);
+ ctor @Deprecated public FragmentTabHost(android.content.Context, android.util.AttributeSet?);
+ method @Deprecated public void addTab(android.widget.TabHost.TabSpec, Class<?>, android.os.Bundle?);
+ method @Deprecated public void onTabChanged(String?);
+ method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager);
+ method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager, int);
+ }
+
+ public abstract class FragmentTransaction {
+ ctor @Deprecated public FragmentTransaction();
+ method public final androidx.fragment.app.FragmentTransaction add(Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+ method public androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.Fragment, String?);
+ method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+ method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment);
+ method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+ method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment, String?);
+ method public androidx.fragment.app.FragmentTransaction addSharedElement(android.view.View, String);
+ method public androidx.fragment.app.FragmentTransaction addToBackStack(String?);
+ method public androidx.fragment.app.FragmentTransaction attach(androidx.fragment.app.Fragment);
+ method public abstract int commit();
+ method public abstract int commitAllowingStateLoss();
+ method public abstract void commitNow();
+ method public abstract void commitNowAllowingStateLoss();
+ method public androidx.fragment.app.FragmentTransaction detach(androidx.fragment.app.Fragment);
+ method public androidx.fragment.app.FragmentTransaction disallowAddToBackStack();
+ method public androidx.fragment.app.FragmentTransaction hide(androidx.fragment.app.Fragment);
+ method public boolean isAddToBackStackAllowed();
+ method public boolean isEmpty();
+ method public androidx.fragment.app.FragmentTransaction remove(androidx.fragment.app.Fragment);
+ method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+ method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment);
+ method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+ method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment, String?);
+ method public androidx.fragment.app.FragmentTransaction runOnCommit(Runnable);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setAllowOptimization(boolean);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(@StringRes int);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(CharSequence?);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(@StringRes int);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(CharSequence?);
+ method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+ method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+ method public androidx.fragment.app.FragmentTransaction setMaxLifecycle(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
+ method public androidx.fragment.app.FragmentTransaction setPrimaryNavigationFragment(androidx.fragment.app.Fragment?);
+ method public androidx.fragment.app.FragmentTransaction setReorderingAllowed(boolean);
+ method public androidx.fragment.app.FragmentTransaction setTransition(int);
+ method @Deprecated public androidx.fragment.app.FragmentTransaction setTransitionStyle(@StyleRes int);
+ method public androidx.fragment.app.FragmentTransaction show(androidx.fragment.app.Fragment);
+ field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+ field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+ field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+ field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+ field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+ field public static final int TRANSIT_NONE = 0; // 0x0
+ field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class FragmentTransitionImpl {
+ ctor public FragmentTransitionImpl();
+ method public abstract void addTarget(Object!, android.view.View!);
+ method public abstract void addTargets(Object!, java.util.ArrayList<android.view.View!>!);
+ method public abstract void beginDelayedTransition(android.view.ViewGroup!, Object!);
+ method protected static void bfsAddViewChildren(java.util.List<android.view.View!>!, android.view.View!);
+ method public abstract boolean canHandle(Object!);
+ method public abstract Object! cloneTransition(Object!);
+ method protected void getBoundsOnScreen(android.view.View!, android.graphics.Rect!);
+ method protected static boolean isNullOrEmpty(java.util.List!);
+ method public abstract Object! mergeTransitionsInSequence(Object!, Object!, Object!);
+ method public abstract Object! mergeTransitionsTogether(Object!, Object!, Object!);
+ method public abstract void removeTarget(Object!, android.view.View!);
+ method public abstract void replaceTargets(Object!, java.util.ArrayList<android.view.View!>!, java.util.ArrayList<android.view.View!>!);
+ method public abstract void scheduleHideFragmentView(Object!, android.view.View!, java.util.ArrayList<android.view.View!>!);
+ method public abstract void scheduleRemoveTargets(Object!, Object!, java.util.ArrayList<android.view.View!>!, Object!, java.util.ArrayList<android.view.View!>!, Object!, java.util.ArrayList<android.view.View!>!);
+ method public abstract void setEpicenter(Object!, android.view.View!);
+ method public abstract void setEpicenter(Object!, android.graphics.Rect!);
+ method public void setListenerForTransitionEnd(androidx.fragment.app.Fragment, Object, androidx.core.os.CancellationSignal, Runnable);
+ method public abstract void setSharedElementTargets(Object!, android.view.View!, java.util.ArrayList<android.view.View!>!);
+ method public abstract void swapSharedElementTargets(Object!, java.util.ArrayList<android.view.View!>!, java.util.ArrayList<android.view.View!>!);
+ method public abstract Object! wrapTransitionInSet(Object!);
+ }
+
+ public class ListFragment extends androidx.fragment.app.Fragment {
+ ctor public ListFragment();
+ method public android.widget.ListAdapter? getListAdapter();
+ method public android.widget.ListView getListView();
+ method public long getSelectedItemId();
+ method public int getSelectedItemPosition();
+ method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+ method public final android.widget.ListAdapter requireListAdapter();
+ method public void setEmptyText(CharSequence?);
+ method public void setListAdapter(android.widget.ListAdapter?);
+ method public void setListShown(boolean);
+ method public void setListShownNoAnimation(boolean);
+ method public void setSelection(int);
+ }
+
+}
+
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt
index e66d0f0..34a7ff9 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt
@@ -224,6 +224,21 @@
verifyPopTransition(1, fragment2, fragment1)
}
+ @Test
+ fun noSharedElementToSharedElement() {
+ val fragment1 = setupInitialFragment()
+
+ // Now do a transition to scene2
+ val fragment2 = SharedElementOnlyTransitionFragment()
+
+ verifyTransition(fragment1, fragment2, "blueSquare")
+
+ // Now pop the back stack
+ verifyPopTransition(1, fragment2, fragment1)
+
+ assertThat(fragment2.destroyViewCountDownLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+ }
+
// Test that shared elements transition from one fragment to the next
// and back during pop.
@Suppress("DEPRECATION")
@@ -1242,9 +1257,11 @@
}
verifyNoOtherTransitions(from)
- to.enterTransition.verifyAndClearTransition {
- epicenter = endBlueRect
- enteringViews += listOfNotNull(endGreen, endRed)
+ if (to.getEnterTransition() != null) {
+ to.enterTransition.verifyAndClearTransition {
+ epicenter = endBlueRect
+ enteringViews += listOfNotNull(endGreen, endRed)
+ }
}
to.sharedElementEnter.verifyAndClearTransition {
@@ -1420,9 +1437,11 @@
val endRed = activityRule.findRed()
val endSharedRect = endBlue.boundsOnScreen
- from.returnTransition.verifyAndClearTransition {
- epicenter = startSharedRect
- exitingViews += listOfNotNull(startGreen, startRed)
+ if (from.getReturnTransition() != null) {
+ from.returnTransition.verifyAndClearTransition {
+ epicenter = startSharedRect
+ exitingViews += listOfNotNull(startGreen, startRed)
+ }
}
from.sharedElementReturn.verifyAndClearTransition {
epicenter = startSharedRect
@@ -1483,6 +1502,28 @@
}
}
+ // Transition fragment with only shared element transitions
+ class SharedElementOnlyTransitionFragment : TransitionFragment(R.layout.scene2) {
+ val destroyViewCountDownLatch = CountDownLatch(1)
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setEnterTransition(null)
+ setReenterTransition(null)
+ setExitTransition(null)
+ setReturnTransition(null)
+ enterTransition.addListener(null)
+ reenterTransition.addListener(null)
+ exitTransition.addListener(null)
+ returnTransition.addListener(null)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ destroyViewCountDownLatch.countDown()
+ }
+ }
+
class TestShowHideTransitionListener(
fragment: TransitionFragment
) : TestTransitionFragmentListener(
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/PrimaryNavFragmentTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/PrimaryNavFragmentTest.kt
index 487b217..26c2dec 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/PrimaryNavFragmentTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/PrimaryNavFragmentTest.kt
@@ -233,7 +233,7 @@
.commit()
executePendingTransactions(fm)
- assertThat(navigations.drain()).isEqualTo(listOf(trackingFragment1 to true))
+ assertThat(navigations.drain()).containsExactly(trackingFragment1 to true).inOrder()
assertWithMessage("new fragment is not primary nav fragment")
.that(fm.primaryNavigationFragment)
.isSameInstanceAs(trackingFragment1)
@@ -246,8 +246,8 @@
.commit()
executePendingTransactions(fm)
- assertThat(navigations.drain()).isEqualTo(
- listOf(trackingFragment1 to false, trackingFragment2 to true))
+ assertThat(navigations.drain()).containsExactly(
+ trackingFragment1 to false, trackingFragment2 to true).inOrder()
assertWithMessage("primary nav fragment not set correctly after replace")
.that(fm.primaryNavigationFragment)
.isSameInstanceAs(trackingFragment2)
@@ -256,7 +256,8 @@
// Note that strictFragment2 does not get a callback since the
// pop of the replace happens before the pop of the setPrimaryFragment
- assertThat(navigations.drain()).isEqualTo(listOf(trackingFragment1 to true))
+ assertThat(navigations.drain()).containsExactly(
+ trackingFragment2 to false, trackingFragment1 to true).inOrder()
assertWithMessage("primary nav fragment is restored after popping replace")
.that(fm.primaryNavigationFragment)
.isSameInstanceAs(trackingFragment1)
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/StrictViewFragment.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/StrictViewFragment.kt
index 5bca8e8..17d7bab 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/StrictViewFragment.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/StrictViewFragment.kt
@@ -69,6 +69,13 @@
assertWithMessage("getView returned null in onDestroyView")
.that(view)
.isNotNull()
+ if (requireView().parent != null &&
+ requireView().animation != null &&
+ FragmentManager.USE_STATE_MANAGER) {
+ assertWithMessage("View should be removed from parent if there is no animation")
+ .that((requireView().parent as ViewGroup).layoutTransition)
+ .isNotNull()
+ }
checkGetActivity()
checkState("onDestroyView", State.CREATED)
onDestroyViewCalled = true
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
index 4bc88fb..ce2159f 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
@@ -443,14 +443,12 @@
throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
}
if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) {
- if (FragmentManager.USE_STATE_MANAGER) {
- mManager.createOrGetFragmentStateManager(f).moveToExpectedState();
- } else {
+ if (!FragmentManager.USE_STATE_MANAGER) {
mManager.moveFragmentToExpectedState(f);
}
}
}
- if (!mReorderingAllowed) {
+ if (!mReorderingAllowed && !FragmentManager.USE_STATE_MANAGER) {
// Added fragments are added at the end to comply with prior behavior.
mManager.moveToState(mManager.mCurState, true);
}
@@ -513,14 +511,12 @@
throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
}
if (!mReorderingAllowed && op.mCmd != OP_REMOVE && f != null) {
- if (FragmentManager.USE_STATE_MANAGER) {
- mManager.createOrGetFragmentStateManager(f).moveToExpectedState();
- } else {
+ if (!FragmentManager.USE_STATE_MANAGER) {
mManager.moveFragmentToExpectedState(f);
}
}
}
- if (!mReorderingAllowed && moveToState) {
+ if (!mReorderingAllowed && moveToState && !FragmentManager.USE_STATE_MANAGER) {
mManager.moveToState(mManager.mCurState, true);
}
}
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java b/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
index dbfc93b..5ce764d 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
@@ -601,7 +601,10 @@
continue;
}
Object transition = transitionInfo.getTransition();
- if (transition != null) {
+ Operation operation = transitionInfo.getOperation();
+ boolean involvedInSharedElementTransition = sharedElementTransition != null
+ && (operation == firstOut || operation == lastIn);
+ if (transition != null || involvedInSharedElementTransition) {
transitionImpl.setListenerForTransitionEnd(
transitionInfo.getOperation().getFragment(),
mergedTransition,
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
index ea8735a..5edfbff 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -2662,7 +2662,8 @@
* Calling postponeEnterTransition on Fragments with a null View will not postpone the
* transition. Likewise, postponement only works if
* {@link FragmentTransaction#setReorderingAllowed(boolean) FragmentTransaction reordering} is
- * enabled.
+ * enabled if you have called {@link FragmentManager#enableNewStateManager(boolean)} with
+ * <code>false</code>.
*
* @see Activity#postponeEnterTransition()
* @see FragmentTransaction#setReorderingAllowed(boolean)
@@ -2694,7 +2695,8 @@
* Calling postponeEnterTransition on Fragments with a null View will not postpone the
* transition. Likewise, postponement only works if
* {@link FragmentTransaction#setReorderingAllowed(boolean) FragmentTransaction reordering} is
- * enabled.
+ * enabled if you have called {@link FragmentManager#enableNewStateManager(boolean)} with
+ * <code>false</code>.
*
* @param duration The length of the delay in {@code timeUnit} units
* @param timeUnit The units of time for {@code duration}
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java
index 89852add..db10bbf 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java
@@ -22,6 +22,7 @@
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -88,11 +89,6 @@
fragment = mFragmentManager.findFragmentById(containerId);
}
- if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
- Log.v(TAG, "onCreateView: id=0x"
- + Integer.toHexString(id) + " fname=" + fname
- + " existing=" + fragment);
- }
FragmentStateManager fragmentStateManager;
if (fragment == null) {
fragment = mFragmentManager.getFragmentFactory().instantiate(
@@ -108,6 +104,10 @@
fragment.mSavedFragmentState);
fragmentStateManager = mFragmentManager.createOrGetFragmentStateManager(fragment);
mFragmentManager.addFragment(fragment);
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG, "Fragment " + fragment + " has been inflated via "
+ + "the <fragment> tag: id=0x" + Integer.toHexString(id));
+ }
} else if (fragment.mInLayout) {
// A fragment already exists and it is not one we restored from
@@ -126,8 +126,16 @@
fragment.onInflate(mFragmentManager.getHost().getContext(), attrs,
fragment.mSavedFragmentState);
fragmentStateManager = mFragmentManager.createOrGetFragmentStateManager(fragment);
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG, "Retained Fragment " + fragment + " has been "
+ + "re-attached via the <fragment> tag: id=0x" + Integer.toHexString(id));
+ }
}
+ // Explicitly set the container for the fragment as we already know
+ // the parent that the fragment will be added to by the LayoutInflater
+ fragment.mContainer = (ViewGroup) parent;
+
// The <fragment> tag is the one case where we:
// 1) Move the Fragment to CREATED even if the FragmentManager isn't yet CREATED
fragmentStateManager.moveToExpectedState();
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index ae73f30..6445a872 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -1419,6 +1419,10 @@
mFragmentTransitionCallback);
}
container.removeView(view);
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG, "Removing view " + view + " for "
+ + "fragment " + f + " from container " + container);
+ }
// If the local container is different from the fragment
// container, that means onAnimationEnd was called, onDestroyView
// was dispatched and the fragment was already moved to state, so
@@ -2149,37 +2153,35 @@
// The last operation determines the overall direction, this ensures that operations
// such as push, push, pop, push are correctly considered a push
boolean isPop = isRecordPop.get(endIndex - 1);
- if (allowReordering) {
- // Ensure that Fragments directly affected by operations
- // are moved to their expected state in operation order
- for (int index = startIndex; index < endIndex; index++) {
- BackStackRecord record = records.get(index);
- if (isPop) {
- // Pop operations get applied in reverse order
- for (int opIndex = record.mOps.size() - 1; opIndex >= 0; opIndex--) {
- FragmentTransaction.Op op = record.mOps.get(opIndex);
- Fragment fragment = op.mFragment;
- if (fragment != null) {
- FragmentStateManager fragmentStateManager =
- createOrGetFragmentStateManager(fragment);
- fragmentStateManager.moveToExpectedState();
- }
- }
- } else {
- for (FragmentTransaction.Op op : record.mOps) {
- Fragment fragment = op.mFragment;
- if (fragment != null) {
- FragmentStateManager fragmentStateManager =
- createOrGetFragmentStateManager(fragment);
- fragmentStateManager.moveToExpectedState();
- }
+ // Ensure that Fragments directly affected by operations
+ // are moved to their expected state in operation order
+ for (int index = startIndex; index < endIndex; index++) {
+ BackStackRecord record = records.get(index);
+ if (isPop) {
+ // Pop operations get applied in reverse order
+ for (int opIndex = record.mOps.size() - 1; opIndex >= 0; opIndex--) {
+ FragmentTransaction.Op op = record.mOps.get(opIndex);
+ Fragment fragment = op.mFragment;
+ if (fragment != null) {
+ FragmentStateManager fragmentStateManager =
+ createOrGetFragmentStateManager(fragment);
+ fragmentStateManager.moveToExpectedState();
}
}
-
+ } else {
+ for (FragmentTransaction.Op op : record.mOps) {
+ Fragment fragment = op.mFragment;
+ if (fragment != null) {
+ FragmentStateManager fragmentStateManager =
+ createOrGetFragmentStateManager(fragment);
+ fragmentStateManager.moveToExpectedState();
+ }
+ }
}
- // And only then do we move all other fragments to the current state
- moveToState(mCurState, true);
+
}
+ // And only then do we move all other fragments to the current state
+ moveToState(mCurState, true);
Set<SpecialEffectsController> changedControllers = collectChangedControllers(
records, startIndex, endIndex);
for (SpecialEffectsController controller : changedControllers) {
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
index 1776ee9..b694598 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
@@ -334,8 +334,7 @@
saveViewState();
}
}
- if (mFragment.mView != null && mFragment.mContainer != null
- && mFragmentManagerState > Fragment.INITIALIZING) {
+ if (mFragment.mView != null && mFragment.mContainer != null) {
SpecialEffectsController controller = SpecialEffectsController
.getOrCreateController(mFragment.mContainer,
mFragment.getParentFragmentManager());
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.java b/fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.java
index e0682f7..94ad2ba 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.java
@@ -16,6 +16,7 @@
package androidx.fragment.app;
+import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -147,18 +148,38 @@
void enqueueAdd(@NonNull Operation.State finalState,
@NonNull FragmentStateManager fragmentStateManager) {
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG,
+ "SpecialEffectsController: Enqueuing add operation for fragment "
+ + fragmentStateManager.getFragment());
+ }
enqueue(finalState, Operation.LifecycleImpact.ADDING, fragmentStateManager);
}
void enqueueShow(@NonNull FragmentStateManager fragmentStateManager) {
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG,
+ "SpecialEffectsController: Enqueuing show operation for fragment "
+ + fragmentStateManager.getFragment());
+ }
enqueue(Operation.State.VISIBLE, Operation.LifecycleImpact.NONE, fragmentStateManager);
}
void enqueueHide(@NonNull FragmentStateManager fragmentStateManager) {
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG,
+ "SpecialEffectsController: Enqueuing hide operation for fragment "
+ + fragmentStateManager.getFragment());
+ }
enqueue(Operation.State.GONE, Operation.LifecycleImpact.NONE, fragmentStateManager);
}
void enqueueRemove(@NonNull FragmentStateManager fragmentStateManager) {
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG,
+ "SpecialEffectsController: Enqueuing remove operation for fragment "
+ + fragmentStateManager.getFragment());
+ }
enqueue(Operation.State.REMOVED, Operation.LifecycleImpact.REMOVING, fragmentStateManager);
}
@@ -205,7 +226,7 @@
void markPostponedState() {
synchronized (mPendingOperations) {
- updateFinalState(false);
+ updateFinalState();
// Default to not postponed
mIsContainerPostponed = false;
for (int index = mPendingOperations.size() - 1; index >= 0; index--) {
@@ -240,6 +261,10 @@
ArrayList<Operation> currentlyRunningOperations = new ArrayList<>(mRunningOperations);
mRunningOperations.clear();
for (Operation operation : currentlyRunningOperations) {
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG,
+ "SpecialEffectsController: Cancelling operation " + operation);
+ }
operation.cancel();
if (!operation.isComplete()) {
// Re-add any animations that didn't synchronously call complete()
@@ -247,12 +272,16 @@
mRunningOperations.add(operation);
}
}
- updateFinalState(true);
+
+ updateFinalState();
if (!mPendingOperations.isEmpty()) {
ArrayList<Operation> newPendingOperations = new ArrayList<>(mPendingOperations);
mPendingOperations.clear();
mRunningOperations.addAll(newPendingOperations);
+ for (Operation operation : newPendingOperations) {
+ operation.onStart();
+ }
executeOperations(newPendingOperations, mOperationDirectionIsPop);
mOperationDirectionIsPop = false;
}
@@ -261,23 +290,36 @@
void forceCompleteAllOperations() {
synchronized (mPendingOperations) {
- updateFinalState(true);
+ updateFinalState();
+ for (Operation operation : mPendingOperations) {
+ operation.onStart();
+ }
// First cancel running operations
ArrayList<Operation> runningOperations = new ArrayList<>(mRunningOperations);
for (Operation operation : runningOperations) {
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG,
+ "SpecialEffectsController: Cancelling running operation "
+ + operation);
+ }
operation.cancel();
}
// Then cancel pending operations
ArrayList<Operation> pendingOperations = new ArrayList<>(mPendingOperations);
for (Operation operation : pendingOperations) {
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG,
+ "SpecialEffectsController: Cancelling pending operation "
+ + operation);
+ }
operation.cancel();
}
}
}
- private void updateFinalState(boolean updateAlpha) {
+ private void updateFinalState() {
for (Operation operation: mPendingOperations) {
// update the final state of adding operations
if (operation.getLifecycleImpact() == Operation.LifecycleImpact.ADDING) {
@@ -285,14 +327,6 @@
View view = fragment.requireView();
Operation.State finalState = Operation.State.from(view.getVisibility());
operation.mergeWith(finalState, Operation.LifecycleImpact.NONE);
- // Change the view alphas back to their original values before we execute our
- // transitions.
- if (updateAlpha) {
- if (view.getAlpha() == 0f && view.getVisibility() == View.VISIBLE) {
- view.setVisibility(View.INVISIBLE);
- }
- view.setAlpha(fragment.getPostOnViewCreatedAlpha());
- }
}
}
}
@@ -396,16 +430,33 @@
case REMOVED:
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null) {
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG, "SpecialEffectsController: Removing "
+ + "view " + view + " from container " + parent);
+ }
parent.removeView(view);
}
break;
case VISIBLE:
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG, "SpecialEffectsController: Setting view "
+ + view + " to VISIBLE");
+ }
view.setVisibility(View.VISIBLE);
break;
case GONE:
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG,
+ "SpecialEffectsController: Setting view " + view + " to GONE");
+ }
view.setVisibility(View.GONE);
break;
case INVISIBLE:
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG,
+ "SpecialEffectsController: Setting view " + view + " to "
+ + "INVISIBLE");
+ }
view.setVisibility(View.INVISIBLE);
break;
}
@@ -499,6 +550,29 @@
return mIsCanceled;
}
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Operation ");
+ sb.append("{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append("} ");
+ sb.append("{");
+ sb.append("mFinalState = ");
+ sb.append(mFinalState);
+ sb.append("} ");
+ sb.append("{");
+ sb.append("mLifecycleImpact = ");
+ sb.append(mLifecycleImpact);
+ sb.append("} ");
+ sb.append("{");
+ sb.append("mFragment = ");
+ sb.append(mFragment);
+ sb.append("}");
+ return sb.toString();
+ }
+
final void cancel() {
if (isCanceled()) {
return;
@@ -518,6 +592,11 @@
switch (lifecycleImpact) {
case ADDING:
if (mFinalState == State.REMOVED) {
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG, "SpecialEffectsController: For fragment "
+ + mFragment + " mFinalState = REMOVED -> VISIBLE. "
+ + "mLifecycleImpact = " + mLifecycleImpact + " to ADDING.");
+ }
// Applying an ADDING operation to a REMOVED fragment
// moves it back to ADDING
mFinalState = State.VISIBLE;
@@ -525,6 +604,11 @@
}
break;
case REMOVING:
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG, "SpecialEffectsController: For fragment "
+ + mFragment + " mFinalState = " + mFinalState + " -> REMOVED. "
+ + "mLifecycleImpact = " + mLifecycleImpact + " to REMOVING.");
+ }
// Any REMOVING operation overrides whatever we had before
mFinalState = State.REMOVED;
mLifecycleImpact = LifecycleImpact.REMOVING;
@@ -532,6 +616,11 @@
case NONE:
// This is a hide or show operation
if (mFinalState != State.REMOVED) {
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG, "SpecialEffectsController: For fragment "
+ + mFragment + " mFinalState = " + mFinalState + " -> "
+ + finalState + ". ");
+ }
mFinalState = finalState;
}
}
@@ -542,11 +631,17 @@
}
/**
+ * Callback for when the operation is about to start.
+ */
+ void onStart() {}
+
+ /**
* Add new {@link CancellationSignal} for special effects.
*
* @param signal A CancellationSignal that can be used to cancel this special effect.
*/
public final void markStartedSpecialEffect(@NonNull CancellationSignal signal) {
+ onStart();
mSpecialEffectsSignals.add(signal);
}
@@ -576,6 +671,10 @@
if (mIsComplete) {
return;
}
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG,
+ "SpecialEffectsController: " + this + " has called complete.");
+ }
mIsComplete = true;
for (Runnable listener : mCompletionListeners) {
listener.run();
@@ -597,6 +696,28 @@
}
@Override
+ void onStart() {
+ Fragment fragment = mFragmentStateManager.getFragment();
+ View focusedView = fragment.mView.findFocus();
+ if (focusedView != null) {
+ fragment.setFocusedView(focusedView);
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG, "requestFocus: Saved focused view " + focusedView
+ + " for Fragment " + fragment);
+ }
+ }
+ if (getLifecycleImpact() == Operation.LifecycleImpact.ADDING) {
+ View view = getFragment().requireView();
+ // Change the view alphas back to their original values before we execute our
+ // transitions.
+ if (view.getAlpha() == 0f && view.getVisibility() == View.VISIBLE) {
+ view.setVisibility(View.INVISIBLE);
+ }
+ view.setAlpha(fragment.getPostOnViewCreatedAlpha());
+ }
+ }
+
+ @Override
public void complete() {
super.complete();
mFragmentStateManager.moveToExpectedState();
diff --git a/gradlew b/gradlew
index b99c9f3..efd6003 100755
--- a/gradlew
+++ b/gradlew
@@ -231,7 +231,7 @@
function runGradle() {
processOutput=false
- if [[ " ${@} " =~ " -Pandroidx.validateNoExtraMessages " ]]; then
+ if [[ " ${@} " =~ " -Pandroidx.validateNoUnrecognizedMessages " ]]; then
processOutput=true
fi
if [[ " ${@} " =~ " -Pandroidx.summarizeStderr " ]]; then
diff --git a/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java b/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
index d1b6cb92..dbfadd6 100644
--- a/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
+++ b/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
@@ -48,6 +48,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
import androidx.test.rule.GrantPermissionRule;
import org.junit.After;
@@ -280,6 +281,25 @@
}
}
+ @Test
+ @SmallTest
+ public void testCloseWithoutStart() throws Throwable {
+ if (shouldSkip()) return;
+
+ final String outputPath = new File(getApplicationContext().getExternalFilesDir(null),
+ OUTPUT_FILENAME).getAbsolutePath();
+ HeifWriter heifWriter = new HeifWriter.Builder(
+ outputPath, 1920, 1080, INPUT_MODE_SURFACE)
+ .setGridEnabled(true)
+ .setMaxImages(4)
+ .setQuality(90)
+ .setPrimaryIndex(0)
+ .setHandler(mHandler)
+ .build();
+
+ heifWriter.close();
+ }
+
private void doTestForVariousNumberImages(TestConfig.Builder builder) throws Exception {
builder.setNumImages(4);
doTest(builder.setRotation(270).build());
diff --git a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
index 025cce9..5e08a73 100644
--- a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
+++ b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
@@ -46,7 +46,6 @@
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.CountDownLatch;
/**
* This class encodes images into HEIF-compatible samples using HEVC encoder.
@@ -128,7 +127,6 @@
private int mTextureId;
private final float[] mTmpMatrix = new float[16];
private final AtomicBoolean mStopping = new AtomicBoolean(false);
- private final CountDownLatch mStoppedLatch;
public static final int INPUT_MODE_BUFFER = HeifWriter.INPUT_MODE_BUFFER;
public static final int INPUT_MODE_SURFACE = HeifWriter.INPUT_MODE_SURFACE;
@@ -380,8 +378,6 @@
mDstRect = new Rect(0, 0, mGridWidth, mGridHeight);
mSrcRect = new Rect();
-
- mStoppedLatch = new CountDownLatch(1);
}
private String findHevcFallback() {
@@ -748,9 +744,13 @@
mStopping.set(true);
// after start, mEncoder is only accessed on handler, so no need to sync.
- if (mEncoder != null) {
- mEncoder.stop();
- mEncoder.release();
+ try {
+ if (mEncoder != null) {
+ mEncoder.stop();
+ mEncoder.release();
+ }
+ } catch (Exception e) {
+ } finally {
mEncoder = null;
}
@@ -768,26 +768,36 @@
// those outputs were not returned. Shutting down the encoder will make break
// the tile copier out of that.
synchronized(this) {
- if (mRectBlt != null) {
- mRectBlt.release(false);
+ try {
+ if (mRectBlt != null) {
+ mRectBlt.release(false);
+ }
+ } catch (Exception e) {
+ } finally {
mRectBlt = null;
}
- if (mEncoderEglSurface != null) {
- // Note that this frees mEncoderSurface too. If mEncoderEglSurface is not
- // there, client is responsible to release the input surface it got from us,
- // we don't release mEncoderSurface here.
- mEncoderEglSurface.release();
+ try {
+ if (mEncoderEglSurface != null) {
+ // Note that this frees mEncoderSurface too. If mEncoderEglSurface is not
+ // there, client is responsible to release the input surface it got from us,
+ // we don't release mEncoderSurface here.
+ mEncoderEglSurface.release();
+ }
+ } catch (Exception e) {
+ } finally {
mEncoderEglSurface = null;
}
- if (mInputTexture != null) {
- mInputTexture.release();
+ try {
+ if (mInputTexture != null) {
+ mInputTexture.release();
+ }
+ } catch (Exception e) {
+ } finally {
mInputTexture = null;
}
}
-
- mStoppedLatch.countDown();
}
/**
@@ -997,11 +1007,12 @@
mHandler.postAtFrontOfQueue(new Runnable() {
@Override
public void run() {
- stopInternal();
+ try {
+ stopInternal();
+ } catch (Exception e) {
+ // We don't want to crash when closing.
+ }
}
});
- try {
- mStoppedLatch.await();
- } catch(InterruptedException e) {}
}
}
diff --git a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java
index db947eb..c086fb5 100644
--- a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java
+++ b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java
@@ -42,7 +42,6 @@
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -104,7 +103,6 @@
@SuppressWarnings("WeakerAccess") /* synthetic access */
int mOutputIndex;
private boolean mStarted;
- private final CountDownLatch mStoppedLatch;
private final List<Pair<Integer, ByteBuffer>> mExifList = new ArrayList<>();
@@ -353,8 +351,6 @@
mHeifEncoder = new HeifEncoder(width, height, gridEnabled, quality,
mInputMode, mHandler, new HeifCallback());
-
- mStoppedLatch = new CountDownLatch(1);
}
/**
@@ -537,21 +533,28 @@
@SuppressWarnings("WeakerAccess") /* synthetic access */
void closeInternal() {
if (DEBUG) Log.d(TAG, "closeInternal");
-
- if (mMuxer != null) {
- mMuxer.stop();
- mMuxer.release();
+ // We don't want to crash when closing, catch all exceptions.
+ try {
+ // Muxer could throw exceptions if stop is called without samples.
+ // Don't crash in that case.
+ if (mMuxer != null) {
+ mMuxer.stop();
+ mMuxer.release();
+ }
+ } catch (Exception e) {
+ } finally {
mMuxer = null;
}
-
- if (mHeifEncoder != null) {
- mHeifEncoder.close();
+ try {
+ if (mHeifEncoder != null) {
+ mHeifEncoder.close();
+ }
+ } catch (Exception e) {
+ } finally {
synchronized (this) {
mHeifEncoder = null;
}
}
-
- mStoppedLatch.countDown();
}
/**
@@ -712,8 +715,5 @@
}
}
});
- try {
- mStoppedLatch.await();
- } catch (InterruptedException e) {}
}
}
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/assisted/AssistedFactoryGenerator.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/assisted/AssistedFactoryGenerator.kt
index 34de592..1257acd 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/assisted/AssistedFactoryGenerator.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/assisted/AssistedFactoryGenerator.kt
@@ -107,8 +107,10 @@
.addModifiers(Modifier.PUBLIC)
.returns(productClassName)
.addParameters(parameterSpecs)
- .addStatement("return new $T($L)",
- productClassName, CodeBlock.join(constructorArgs, ",$W"))
+ .addStatement(
+ "return new $T($L)",
+ productClassName, CodeBlock.join(constructorArgs, ",$W")
+ )
.build()
}
}
\ No newline at end of file
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelGenerator.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelGenerator.kt
index bd1225f..af92a93 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelGenerator.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelGenerator.kt
@@ -88,7 +88,8 @@
.addAnnotation(
AnnotationSpec.builder(ClassNames.INSTALL_IN)
.addMember("value", "$T.class", ClassNames.ACTIVITY_RETAINED_COMPONENT)
- .build())
+ .build()
+ )
.addAnnotation(
AnnotationSpec.builder(ClassNames.ORIGINATING_ELEMENT)
.addMember(
@@ -106,14 +107,18 @@
.addAnnotation(
AnnotationSpec.builder(ClassNames.STRING_KEY)
.addMember("value", S, injectedViewModel.className.reflectionName())
- .build())
+ .build()
+ )
.addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
.returns(
ParameterizedTypeName.get(
ClassNames.VIEW_MODEL_ASSISTED_FACTORY,
- WildcardTypeName.subtypeOf(ClassNames.VIEW_MODEL)))
+ WildcardTypeName.subtypeOf(ClassNames.VIEW_MODEL)
+ )
+ )
.addParameter(injectedViewModel.factoryClassName, "factory")
- .build())
+ .build()
+ )
.build()
JavaFile.builder(injectedViewModel.moduleClassName.packageName(), hiltModuleTypeSpec)
.build()
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectElements.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectElements.kt
index 206c4f6..a7bf032 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectElements.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectElements.kt
@@ -35,15 +35,18 @@
val factoryClassName = ClassName.get(
MoreElements.getPackage(typeElement).qualifiedName.toString(),
- "${className.simpleNames().joinToString("_")}_AssistedFactory")
+ "${className.simpleNames().joinToString("_")}_AssistedFactory"
+ )
val factorySuperTypeName = ParameterizedTypeName.get(
ClassNames.VIEW_MODEL_ASSISTED_FACTORY,
- className)
+ className
+ )
val moduleClassName = ClassName.get(
MoreElements.getPackage(typeElement).qualifiedName.toString(),
- "${className.simpleNames().joinToString("_")}_HiltModule")
+ "${className.simpleNames().joinToString("_")}_HiltModule"
+ )
val dependencyRequests = constructorElement.parameters.map { constructorArg ->
constructorArg.toDependencyRequest()
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectStep.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectStep.kt
index ec7bf75..c86a7bf 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectStep.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectStep.kt
@@ -66,15 +66,22 @@
var valid = true
if (elements.getTypeElement(ClassNames.VIEW_MODEL_ASSISTED_FACTORY.toString()) == null) {
- error("To use @ViewModelInject you must add the 'lifecycle-viewmodel' " +
- "artifact. androidx.hilt:hilt-lifecyclew-viewmodel:<version>")
+ error(
+ "To use @ViewModelInject you must add the 'lifecycle-viewmodel' " +
+ "artifact. androidx.hilt:hilt-lifecyclew-viewmodel:<version>"
+ )
valid = false
}
- if (!types.isSubtype(typeElement.asType(),
- elements.getTypeElement(ClassNames.VIEW_MODEL.toString()).asType())) {
- error("@ViewModelInject is only supported on types that subclass " +
- "${ClassNames.VIEW_MODEL}.")
+ if (!types.isSubtype(
+ typeElement.asType(),
+ elements.getTypeElement(ClassNames.VIEW_MODEL.toString()).asType()
+ )
+ ) {
+ error(
+ "@ViewModelInject is only supported on types that subclass " +
+ "${ClassNames.VIEW_MODEL}."
+ )
valid = false
}
@@ -92,9 +99,12 @@
}
if (typeElement.nestingKind == NestingKind.MEMBER &&
- !typeElement.modifiers.contains(Modifier.STATIC)) {
- error("@ViewModelInject may only be used on inner classes if they are static.",
- typeElement)
+ !typeElement.modifiers.contains(Modifier.STATIC)
+ ) {
+ error(
+ "@ViewModelInject may only be used on inner classes if they are static.",
+ typeElement
+ )
valid = false
}
@@ -103,8 +113,11 @@
TypeName.get(it.asType()) == ClassNames.SAVED_STATE_HANDLE
}.apply {
if (size > 1) {
- error("Expected zero or one constructor argument of type " +
- "${ClassNames.SAVED_STATE_HANDLE}, found $size", constructorElement)
+ error(
+ "Expected zero or one constructor argument of type " +
+ "${ClassNames.SAVED_STATE_HANDLE}, found $size",
+ constructorElement
+ )
valid = false
}
firstOrNull()?.let {
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerGenerator.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerGenerator.kt
index 95b3d43..3552dfc 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerGenerator.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerGenerator.kt
@@ -88,7 +88,8 @@
.addAnnotation(
AnnotationSpec.builder(ClassNames.INSTALL_IN)
.addMember("value", "$T.class", ClassNames.SINGLETON_COMPONENT)
- .build())
+ .build()
+ )
.addAnnotation(
AnnotationSpec.builder(ClassNames.ORIGINATING_ELEMENT)
.addMember(
@@ -106,14 +107,18 @@
.addAnnotation(
AnnotationSpec.builder(ClassNames.STRING_KEY)
.addMember("value", S, injectedWorker.className.reflectionName())
- .build())
+ .build()
+ )
.addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
.returns(
ParameterizedTypeName.get(
ClassNames.WORKER_ASSISTED_FACTORY,
- WildcardTypeName.subtypeOf(ClassNames.LISTENABLE_WORKER)))
+ WildcardTypeName.subtypeOf(ClassNames.LISTENABLE_WORKER)
+ )
+ )
.addParameter(injectedWorker.factoryClassName, "factory")
- .build())
+ .build()
+ )
.build()
JavaFile.builder(injectedWorker.moduleClassName.packageName(), hiltModuleTypeSpec)
.build()
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectElements.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectElements.kt
index 5f830a6..03f4c05 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectElements.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectElements.kt
@@ -35,15 +35,18 @@
val factoryClassName = ClassName.get(
MoreElements.getPackage(typeElement).qualifiedName.toString(),
- "${className.simpleNames().joinToString("_")}_AssistedFactory")
+ "${className.simpleNames().joinToString("_")}_AssistedFactory"
+ )
val factorySuperTypeName = ParameterizedTypeName.get(
ClassNames.WORKER_ASSISTED_FACTORY,
- className)
+ className
+ )
val moduleClassName = ClassName.get(
MoreElements.getPackage(typeElement).qualifiedName.toString(),
- "${className.simpleNames().joinToString("_")}_HiltModule")
+ "${className.simpleNames().joinToString("_")}_HiltModule"
+ )
val dependencyRequests = constructorElement.parameters.map { constructorArg ->
constructorArg.toDependencyRequest()
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectStep.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectStep.kt
index 3e5c77d..346f308 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectStep.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectStep.kt
@@ -68,15 +68,22 @@
var valid = true
if (elements.getTypeElement(ClassNames.WORKER_ASSISTED_FACTORY.toString()) == null) {
- error("To use @WorkerInject you must add the 'work' artifact. " +
- "androidx.hilt:hilt-work:<version>")
+ error(
+ "To use @WorkerInject you must add the 'work' artifact. " +
+ "androidx.hilt:hilt-work:<version>"
+ )
valid = false
}
- if (!types.isSubtype(typeElement.asType(),
- elements.getTypeElement(ClassNames.LISTENABLE_WORKER.toString()).asType())) {
- error("@WorkerInject is only supported on types that subclass " +
- "${ClassNames.LISTENABLE_WORKER}.")
+ if (!types.isSubtype(
+ typeElement.asType(),
+ elements.getTypeElement(ClassNames.LISTENABLE_WORKER.toString()).asType()
+ )
+ ) {
+ error(
+ "@WorkerInject is only supported on types that subclass " +
+ "${ClassNames.LISTENABLE_WORKER}."
+ )
valid = false
}
@@ -94,9 +101,12 @@
}
if (typeElement.nestingKind == NestingKind.MEMBER &&
- !typeElement.modifiers.contains(Modifier.STATIC)) {
- error("@WorkerInject may only be used on inner classes if they are static.",
- typeElement)
+ !typeElement.modifiers.contains(Modifier.STATIC)
+ ) {
+ error(
+ "@WorkerInject may only be used on inner classes if they are static.",
+ typeElement
+ )
valid = false
}
@@ -104,8 +114,11 @@
TypeName.get(it.asType()) == ClassNames.CONTEXT
}.apply {
if (size != 1) {
- error("Expected exactly one constructor argument of type " +
- "${ClassNames.CONTEXT}, found $size", constructorElement)
+ error(
+ "Expected exactly one constructor argument of type " +
+ "${ClassNames.CONTEXT}, found $size",
+ constructorElement
+ )
valid = false
}
firstOrNull()?.let {
@@ -120,8 +133,11 @@
TypeName.get(it.asType()) == ClassNames.WORKER_PARAMETERS
}.apply {
if (size != 1) {
- error("Expected exactly one constructor argument of type " +
- "${ClassNames.WORKER_PARAMETERS}, found $size", constructorElement)
+ error(
+ "Expected exactly one constructor argument of type " +
+ "${ClassNames.WORKER_PARAMETERS}, found $size",
+ constructorElement
+ )
valid = false
}
firstOrNull()?.let {
diff --git a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelGeneratorTest.kt b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelGeneratorTest.kt
index 2711070..b150e7f 100644
--- a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelGeneratorTest.kt
+++ b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelGeneratorTest.kt
@@ -458,11 +458,15 @@
.compile(viewModel, Sources.VIEW_MODEL, Sources.SAVED_STATE_HANDLE)
assertThat(compilation).apply {
succeeded()
- generatedSourceFile("androidx.hilt.lifecycle.test" +
- ".Outer_InnerViewModel_AssistedFactory")
+ generatedSourceFile(
+ "androidx.hilt.lifecycle.test" +
+ ".Outer_InnerViewModel_AssistedFactory"
+ )
.hasSourceEquivalentTo(expectedFactory)
- generatedSourceFile("androidx.hilt.lifecycle.test" +
- ".Outer_InnerViewModel_HiltModule")
+ generatedSourceFile(
+ "androidx.hilt.lifecycle.test" +
+ ".Outer_InnerViewModel_HiltModule"
+ )
.hasSourceEquivalentTo(expectedModule)
}
}
diff --git a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelInjectStepTest.kt b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelInjectStepTest.kt
index 8b764a1..3a01a49 100644
--- a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelInjectStepTest.kt
+++ b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelInjectStepTest.kt
@@ -42,7 +42,8 @@
""".toJFO("androidx.hilt.lifecycle.test.MyViewModel")
val compilation = compiler()
- .compile(myViewModel,
+ .compile(
+ myViewModel,
Sources.VIEW_MODEL,
Sources.SAVED_STATE_HANDLE
)
@@ -67,8 +68,10 @@
assertThat(compilation).apply {
failed()
hadErrorCount(1)
- hadErrorContainingMatch("@ViewModelInject is only supported on types that subclass " +
- "androidx.lifecycle.ViewModel.")
+ hadErrorContainingMatch(
+ "@ViewModelInject is only supported on types that subclass " +
+ "androidx.lifecycle.ViewModel."
+ )
}
}
@@ -117,8 +120,10 @@
assertThat(compilation).apply {
failed()
hadErrorCount(1)
- hadErrorContainingMatch("@ViewModelInject annotated constructors must not be " +
- "private.")
+ hadErrorContainingMatch(
+ "@ViewModelInject annotated constructors must not be " +
+ "private."
+ )
}
}
@@ -143,8 +148,10 @@
assertThat(compilation).apply {
failed()
hadErrorCount(1)
- hadErrorContainingMatch("@ViewModelInject may only be used on inner classes " +
- "if they are static.")
+ hadErrorContainingMatch(
+ "@ViewModelInject may only be used on inner classes " +
+ "if they are static."
+ )
}
}
@@ -166,15 +173,18 @@
""".toJFO("androidx.hilt.lifecycle.test.MyViewModel")
val compilation = compiler()
- .compile(myViewModel,
+ .compile(
+ myViewModel,
Sources.VIEW_MODEL,
Sources.SAVED_STATE_HANDLE
)
assertThat(compilation).apply {
failed()
hadErrorCount(1)
- hadErrorContainingMatch("Expected zero or one constructor argument of type " +
- "androidx.lifecycle.SavedStateHandle, found 2")
+ hadErrorContainingMatch(
+ "Expected zero or one constructor argument of type " +
+ "androidx.lifecycle.SavedStateHandle, found 2"
+ )
}
}
@@ -194,7 +204,8 @@
""".toJFO("androidx.hilt.lifecycle.test.MyViewModel")
val compilation = compiler()
- .compile(myViewModel,
+ .compile(
+ myViewModel,
Sources.VIEW_MODEL,
Sources.SAVED_STATE_HANDLE
)
diff --git a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerGeneratorTest.kt b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerGeneratorTest.kt
index 5fd1cc0..b7e8cdad 100644
--- a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerGeneratorTest.kt
+++ b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerGeneratorTest.kt
@@ -94,8 +94,10 @@
""".toJFO("androidx.hilt.work.test.MyWorker_AssistedFactory")
val compilation = compiler()
- .compile(foo, myWorker, Sources.LISTENABLE_WORKER, Sources.WORKER,
- Sources.WORKER_PARAMETERS)
+ .compile(
+ foo, myWorker, Sources.LISTENABLE_WORKER, Sources.WORKER,
+ Sources.WORKER_PARAMETERS
+ )
assertThat(compilation).apply {
succeeded()
generatedSourceFile("androidx.hilt.work.test.MyWorker_AssistedFactory")
diff --git a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerInjectStepTest.kt b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerInjectStepTest.kt
index bf92381..0f83fb6 100644
--- a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerInjectStepTest.kt
+++ b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerInjectStepTest.kt
@@ -48,8 +48,10 @@
assertThat(compilation).apply {
failed()
hadErrorCount(1)
- hadErrorContainingMatch("@WorkerInject is only supported on types that subclass " +
- "androidx.work.ListenableWorker.")
+ hadErrorContainingMatch(
+ "@WorkerInject is only supported on types that subclass " +
+ "androidx.work.ListenableWorker."
+ )
}
}
@@ -111,8 +113,10 @@
assertThat(compilation).apply {
failed()
hadErrorCount(1)
- hadErrorContainingMatch("@WorkerInject annotated constructors must not be " +
- "private.")
+ hadErrorContainingMatch(
+ "@WorkerInject annotated constructors must not be " +
+ "private."
+ )
}
}
@@ -142,8 +146,10 @@
assertThat(compilation).apply {
failed()
hadErrorCount(1)
- hadErrorContainingMatch("@WorkerInject may only be used on inner classes " +
- "if they are static.")
+ hadErrorContainingMatch(
+ "@WorkerInject may only be used on inner classes " +
+ "if they are static."
+ )
}
}
}
\ No newline at end of file
diff --git a/leanback/leanback-paging/src/androidTest/java/androidx/leanback/paging/PagingDataAdapterTest.kt b/leanback/leanback-paging/src/androidTest/java/androidx/leanback/paging/PagingDataAdapterTest.kt
index b2c47b2..fc22370 100644
--- a/leanback/leanback-paging/src/androidTest/java/androidx/leanback/paging/PagingDataAdapterTest.kt
+++ b/leanback/leanback-paging/src/androidTest/java/androidx/leanback/paging/PagingDataAdapterTest.kt
@@ -63,14 +63,17 @@
fun testGetItem() = testScope.runBlockingTest {
val pagingSource = TestPagingSource()
val pagingDataAdapter =
- PagingDataAdapter(diffCallback = object : DiffUtil.ItemCallback<Int>() {
- override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
- return oldItem == newItem
- }
- override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
- return oldItem == newItem
- }
- }, workerDispatcher = Dispatchers.Main)
+ PagingDataAdapter(
+ diffCallback = object : DiffUtil.ItemCallback<Int>() {
+ override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
+ return oldItem == newItem
+ }
+ override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
+ return oldItem == newItem
+ }
+ },
+ workerDispatcher = Dispatchers.Main
+ )
val refreshEvents = mutableListOf<Boolean>()
pagingDataAdapter.addDataRefreshListener { refreshEvents.add(it) }
val pager = Pager(
@@ -102,14 +105,17 @@
@Test
fun testDataRefreshListenerCallbacks() = testScope.runBlockingTest {
val pagingDataAdapter =
- PagingDataAdapter(diffCallback = object : DiffUtil.ItemCallback<Int>() {
- override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
- return oldItem == newItem
- }
- override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
- return oldItem == newItem
- }
- }, workerDispatcher = Dispatchers.Main)
+ PagingDataAdapter(
+ diffCallback = object : DiffUtil.ItemCallback<Int>() {
+ override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
+ return oldItem == newItem
+ }
+ override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
+ return oldItem == newItem
+ }
+ },
+ workerDispatcher = Dispatchers.Main
+ )
val refreshEvents = mutableListOf<Boolean>()
pagingDataAdapter.addDataRefreshListener { refreshEvents.add(it) }
val pager = Pager(
@@ -145,14 +151,17 @@
@Test
fun testLoadStateListenerCallbacks() = testScope.runBlockingTest {
val pagingDataAdapter =
- PagingDataAdapter(diffCallback = object : DiffUtil.ItemCallback<Int>() {
- override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
- return oldItem == newItem
- }
- override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
- return oldItem == newItem
- }
- }, workerDispatcher = Dispatchers.Main)
+ PagingDataAdapter(
+ diffCallback = object : DiffUtil.ItemCallback<Int>() {
+ override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
+ return oldItem == newItem
+ }
+ override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
+ return oldItem == newItem
+ }
+ },
+ workerDispatcher = Dispatchers.Main
+ )
val loadEvents = mutableListOf<CombinedLoadStates>()
pagingDataAdapter.addLoadStateListener { loadEvents.add(it) }
val pager = Pager(
diff --git a/leanback/leanback/src/main/res/values-as/strings.xml b/leanback/leanback/src/main/res/values-as/strings.xml
index aaba187..0d47c7f3 100644
--- a/leanback/leanback/src/main/res/values-as/strings.xml
+++ b/leanback/leanback/src/main/res/values-as/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="lb_navigation_menu_contentDescription" msgid="8084428500709675515">"নেভিগেশ্বন মেনু"</string>
<string name="orb_search_action" msgid="1301877238242752863">"সন্ধান সম্পৰ্কীয় কাৰ্য"</string>
- <string name="lb_search_bar_hint" msgid="5700349211583074131">"সন্ধান"</string>
+ <string name="lb_search_bar_hint" msgid="5700349211583074131">"Search"</string>
<string name="lb_search_bar_hint_speech" msgid="5926531297066387462">"সন্ধান কৰিবলৈ কথা কওক"</string>
<string name="lb_search_bar_hint_with_title" msgid="4826526877249029043">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> সন্ধান কৰক"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="6032250334706920550">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> সন্ধান কৰিবলৈ কথা কওক"</string>
diff --git a/leanback/leanback/src/main/res/values-eu/strings.xml b/leanback/leanback/src/main/res/values-eu/strings.xml
index bc7f0f3..a4529bd 100644
--- a/leanback/leanback/src/main/res/values-eu/strings.xml
+++ b/leanback/leanback/src/main/res/values-eu/strings.xml
@@ -47,7 +47,7 @@
<string name="lb_playback_controls_high_quality_disable" msgid="1209119371486219736">"Desgaitu kalitate handiko erreprodukzioa"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2346334170216706076">"Gaitu azpitituluak"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="8691966842977635128">"Desgaitu azpitituluak"</string>
- <string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"Aktibatu \"Pantaila txiki gainjarri\" modua"</string>
+ <string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"Aktibatu pantaila txiki gainjarriko modua"</string>
<string name="lb_playback_time_separator" msgid="1471121602610716654">"/"</string>
<string name="lb_playback_controls_shown" msgid="8690223891515602822">"Multimedia-edukia kontrolatzeko aukerak ikusgai"</string>
<string name="lb_playback_controls_hidden" msgid="5859666950961624736">"Ezkutatuta daude multimedia-edukia kontrolatzeko aukerak. Haiek erakusteko, sakatu nabigazio-gurutzea."</string>
diff --git a/leanback/leanback/src/main/res/values-fr-rCA/strings.xml b/leanback/leanback/src/main/res/values-fr-rCA/strings.xml
index 4f0d856..8bc2af9 100644
--- a/leanback/leanback/src/main/res/values-fr-rCA/strings.xml
+++ b/leanback/leanback/src/main/res/values-fr-rCA/strings.xml
@@ -34,8 +34,8 @@
<string name="lb_playback_controls_skip_next" msgid="8117512422682146745">"Passer à l\'élément suivant"</string>
<string name="lb_playback_controls_skip_previous" msgid="3481218248309447059">"Retourner à l\'élément précédent"</string>
<string name="lb_playback_controls_more_actions" msgid="8730341244454469032">"Autres actions"</string>
- <string name="lb_playback_controls_thumb_up" msgid="3458671378107738666">"Désélectionner la mention « J\'aime »"</string>
- <string name="lb_playback_controls_thumb_up_outline" msgid="1385865732502550659">"Sélectionner la mention « J\'aime »"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="3458671378107738666">"Désélectionner la mention J\'aime"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1385865732502550659">"Sélectionner la mention J\'aime"</string>
<string name="lb_playback_controls_thumb_down" msgid="3544533410444618518">"Désélectionner la mention « Je n\'aime pas »"</string>
<string name="lb_playback_controls_thumb_down_outline" msgid="8475278766138652105">"Sélectionner la mention « Je n\'aime pas »"</string>
<string name="lb_playback_controls_repeat_none" msgid="1614290959784265209">"Aucune répétition"</string>
diff --git a/leanback/leanback/src/main/res/values-gl/strings.xml b/leanback/leanback/src/main/res/values-gl/strings.xml
index 3b77766..83ddff9 100644
--- a/leanback/leanback/src/main/res/values-gl/strings.xml
+++ b/leanback/leanback/src/main/res/values-gl/strings.xml
@@ -29,8 +29,8 @@
<string name="lb_playback_controls_pause" msgid="917331776961802657">"Pausar"</string>
<string name="lb_playback_controls_fast_forward" msgid="740570111678243493">"Avance rápido"</string>
<string name="lb_playback_controls_fast_forward_multiplier" msgid="5734614175721471329">"Avance rápido %1$dX"</string>
- <string name="lb_playback_controls_rewind" msgid="2866333981131020771">"Rebobinar"</string>
- <string name="lb_playback_controls_rewind_multiplier" msgid="6038956370475252734">"Rebobinado %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2866333981131020771">"Retroceder"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="6038956370475252734">"Retroceso %1$dX"</string>
<string name="lb_playback_controls_skip_next" msgid="8117512422682146745">"Saltar ao seguinte"</string>
<string name="lb_playback_controls_skip_previous" msgid="3481218248309447059">"Saltar ao anterior"</string>
<string name="lb_playback_controls_more_actions" msgid="8730341244454469032">"Máis accións"</string>
diff --git a/leanback/leanback/src/main/res/values-kn/strings.xml b/leanback/leanback/src/main/res/values-kn/strings.xml
index 4cdd8a6..c49761f 100644
--- a/leanback/leanback/src/main/res/values-kn/strings.xml
+++ b/leanback/leanback/src/main/res/values-kn/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="lb_navigation_menu_contentDescription" msgid="8084428500709675515">"ನ್ಯಾವಿಗೇಶನ್ ಮೆನು"</string>
<string name="orb_search_action" msgid="1301877238242752863">"ಹುಡುಕಾಟ ಕ್ರಿಯೆ"</string>
- <string name="lb_search_bar_hint" msgid="5700349211583074131">"ಹುಡುಕಿ"</string>
+ <string name="lb_search_bar_hint" msgid="5700349211583074131">"Search"</string>
<string name="lb_search_bar_hint_speech" msgid="5926531297066387462">"ಹುಡುಕಲು ಮಾತನಾಡಿ"</string>
<string name="lb_search_bar_hint_with_title" msgid="4826526877249029043">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ಹುಡುಕಿ"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="6032250334706920550">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ಮಾತನಾಡಿ ಹುಡುಕಾಟ ನಡೆಸಿ"</string>
diff --git a/leanback/leanback/src/main/res/values-ml/strings.xml b/leanback/leanback/src/main/res/values-ml/strings.xml
index 2122b08..58570f9 100644
--- a/leanback/leanback/src/main/res/values-ml/strings.xml
+++ b/leanback/leanback/src/main/res/values-ml/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="lb_navigation_menu_contentDescription" msgid="8084428500709675515">"നാവിഗേഷൻ മെനു"</string>
<string name="orb_search_action" msgid="1301877238242752863">"തിരയൽ പ്രവർത്തനം"</string>
- <string name="lb_search_bar_hint" msgid="5700349211583074131">"തിരയുക"</string>
+ <string name="lb_search_bar_hint" msgid="5700349211583074131">"Search"</string>
<string name="lb_search_bar_hint_speech" msgid="5926531297066387462">"ശബ്ദം ഉപയോഗിച്ച് തിരയുക"</string>
<string name="lb_search_bar_hint_with_title" msgid="4826526877249029043">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> തിരയുക"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="6032250334706920550">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> തിരയുന്നതിന് സംസാരിക്കുക"</string>
diff --git a/leanback/leanback/src/main/res/values-mr/strings.xml b/leanback/leanback/src/main/res/values-mr/strings.xml
index 17a5a38..94c2c5c 100644
--- a/leanback/leanback/src/main/res/values-mr/strings.xml
+++ b/leanback/leanback/src/main/res/values-mr/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="lb_navigation_menu_contentDescription" msgid="8084428500709675515">"नेव्हिगेशन मेनू"</string>
<string name="orb_search_action" msgid="1301877238242752863">"शोध क्रिया"</string>
- <string name="lb_search_bar_hint" msgid="5700349211583074131">"शोधा"</string>
+ <string name="lb_search_bar_hint" msgid="5700349211583074131">"Search"</string>
<string name="lb_search_bar_hint_speech" msgid="5926531297066387462">"शोधण्यासाठी बोला"</string>
<string name="lb_search_bar_hint_with_title" msgid="4826526877249029043">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> शोधा"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="6032250334706920550">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> शोधण्यासाठी बोला"</string>
diff --git a/leanback/leanback/src/main/res/values-ne/strings.xml b/leanback/leanback/src/main/res/values-ne/strings.xml
index ff431f5..6e05863 100644
--- a/leanback/leanback/src/main/res/values-ne/strings.xml
+++ b/leanback/leanback/src/main/res/values-ne/strings.xml
@@ -47,7 +47,7 @@
<string name="lb_playback_controls_high_quality_disable" msgid="1209119371486219736">"उच्च गुणस्तरलाई असक्षम पार्नुहोस्"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2346334170216706076">"उप शीर्षकहरू देखाउने सुविधालाई सक्षम पार्नुहोस्"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="8691966842977635128">"उप शीर्षकहरू देखाउने सुविधालाई असक्षम पार्नुहोस्"</string>
- <string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"तस्बिरभित्र तस्बिर नामक मोडमा प्रविष्टि गर्नुहोस्"</string>
+ <string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"फोटोभित्र फोटो नामक मोडमा प्रविष्टि गर्नुहोस्"</string>
<string name="lb_playback_time_separator" msgid="1471121602610716654">"/"</string>
<string name="lb_playback_controls_shown" msgid="8690223891515602822">"मिडियाका नियन्त्रणहरू देखाइएका छन्"</string>
<string name="lb_playback_controls_hidden" msgid="5859666950961624736">"मिडियाका नियन्त्रणहरूलाई लुकाइएको छ, देखाउनका लागि d-pad नामक बटन थिच्नुहोस्"</string>
diff --git a/leanback/leanback/src/main/res/values-or/strings.xml b/leanback/leanback/src/main/res/values-or/strings.xml
index 3fb650a..94d6eb3 100644
--- a/leanback/leanback/src/main/res/values-or/strings.xml
+++ b/leanback/leanback/src/main/res/values-or/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="lb_navigation_menu_contentDescription" msgid="8084428500709675515">"ନେଭିଗେଶନ୍ ମେନୁ"</string>
<string name="orb_search_action" msgid="1301877238242752863">"ଖୋଜିବା କାମ"</string>
- <string name="lb_search_bar_hint" msgid="5700349211583074131">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+ <string name="lb_search_bar_hint" msgid="5700349211583074131">"Search"</string>
<string name="lb_search_bar_hint_speech" msgid="5926531297066387462">"ଖୋଜିବା ପାଇଁ କୁହନ୍ତୁ"</string>
<string name="lb_search_bar_hint_with_title" msgid="4826526877249029043">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ଖୋଜନ୍ତୁ"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="6032250334706920550">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ଖୋଜିବା ପାଇଁ କୁହନ୍ତୁ"</string>
diff --git a/leanback/leanback/src/main/res/values-te/strings.xml b/leanback/leanback/src/main/res/values-te/strings.xml
index 372b590..5662227 100644
--- a/leanback/leanback/src/main/res/values-te/strings.xml
+++ b/leanback/leanback/src/main/res/values-te/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="lb_navigation_menu_contentDescription" msgid="8084428500709675515">"నావిగేషన్ మెను"</string>
<string name="orb_search_action" msgid="1301877238242752863">"శోధన చర్య"</string>
- <string name="lb_search_bar_hint" msgid="5700349211583074131">"శోధన"</string>
+ <string name="lb_search_bar_hint" msgid="5700349211583074131">"సెర్చ్"</string>
<string name="lb_search_bar_hint_speech" msgid="5926531297066387462">"శోధించడానికి మాటల ద్వారా చెప్పండి"</string>
<string name="lb_search_bar_hint_with_title" msgid="4826526877249029043">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> కోసం వెతకండి"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="6032250334706920550">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>లో శోధించడానికి మాటల ద్వారా చెప్పండి"</string>
diff --git a/media2/session/src/main/res/values-pt-rPT/strings.xml b/media2/session/src/main/res/values-pt-rPT/strings.xml
index 413b9a6..48a0151 100644
--- a/media2/session/src/main/res/values-pt-rPT/strings.xml
+++ b/media2/session/src/main/res/values-pt-rPT/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="default_notification_channel_name" msgid="6743534657295236036">"A tocar"</string>
<string name="play_button_content_description" msgid="6034272287948142298">"Reproduzir"</string>
- <string name="pause_button_content_description" msgid="4221330012095125431">"Colocar em pausa"</string>
+ <string name="pause_button_content_description" msgid="4221330012095125431">"Pausar"</string>
<string name="skip_to_previous_item_button_content_description" msgid="7233771088610629683">"Ir para o item anterior"</string>
<string name="skip_to_next_item_button_content_description" msgid="17824442457643717">"Ir para o item seguinte"</string>
</resources>
diff --git a/media2/widget/src/main/res/values-cs/strings.xml b/media2/widget/src/main/res/values-cs/strings.xml
index 139c9bf..f14483d 100644
--- a/media2/widget/src/main/res/values-cs/strings.xml
+++ b/media2/widget/src/main/res/values-cs/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="MediaControlView_subtitle_off_text" msgid="1845015629089301203">"Vyp"</string>
+ <string name="MediaControlView_subtitle_off_text" msgid="1845015629089301203">"Vyp."</string>
<string name="MediaControlView_audio_track_text" msgid="3532548952520840186">"Zvuková stopa"</string>
<string name="MediaControlView_audio_track_none_text" msgid="549548876131348304">"Žádné"</string>
<string name="MediaControlView_playback_speed_text" msgid="8150324864582460559">"Rychlost přehrávání"</string>
diff --git a/media2/widget/src/main/res/values-pt-rPT/strings.xml b/media2/widget/src/main/res/values-pt-rPT/strings.xml
index 078266f..697f595 100644
--- a/media2/widget/src/main/res/values-pt-rPT/strings.xml
+++ b/media2/widget/src/main/res/values-pt-rPT/strings.xml
@@ -40,7 +40,7 @@
<string name="mcv2_cc_is_off" msgid="6888583680833967030">"As legendas estão desativadas. Clique para as mostrar."</string>
<string name="mcv2_replay_button_desc" msgid="3498082316888662782">"Repetir"</string>
<string name="mcv2_play_button_desc" msgid="1994649551115596877">"Reproduzir"</string>
- <string name="mcv2_pause_button_desc" msgid="997297527148989963">"Colocar em pausa"</string>
+ <string name="mcv2_pause_button_desc" msgid="997297527148989963">"Pausar"</string>
<string name="mcv2_previous_button_desc" msgid="5367141424871007842">"Conteúdo multimédia anterior"</string>
<string name="mcv2_next_button_desc" msgid="4799850472802157220">"Conteúdo multimédia seguinte"</string>
<string name="mcv2_rewind_button_desc" msgid="5725552141091554735">"Recuar 10 segundos"</string>
diff --git a/mediarouter/mediarouter/src/androidTest/AndroidManifest.xml b/mediarouter/mediarouter/src/androidTest/AndroidManifest.xml
index 512bb09..0b06c49 100644
--- a/mediarouter/mediarouter/src/androidTest/AndroidManifest.xml
+++ b/mediarouter/mediarouter/src/androidTest/AndroidManifest.xml
@@ -38,6 +38,12 @@
</intent-filter>
</receiver>
+ <service android:name="androidx.mediarouter.media.MediaRouteProviderServiceTest$MediaRouteProviderServiceImpl"
+ android:enabled="true">
+ <intent-filter>
+ <action android:name="aandroid.media.MediaRouteProviderService"/>
+ </intent-filter>
+ </service>
</application>
</manifest>
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouteProviderServiceTest.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouteProviderServiceTest.java
new file mode 100644
index 0000000..287ac3b
--- /dev/null
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouteProviderServiceTest.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2020 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 androidx.mediarouter.media;
+
+import static androidx.mediarouter.media.MediaRouterActiveScanThrottlingHelper.MAX_ACTIVE_SCAN_DURATION_MS;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ServiceTestRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test {@link MediaRouteProviderService} and its related classes.
+ */
+@RunWith(AndroidJUnit4.class)
+public class MediaRouteProviderServiceTest {
+ private static final long TIME_OUT_MS = 3000;
+
+ @Rule
+ public final ServiceTestRule mServiceRule = new ServiceTestRule();
+ private IBinder mService;
+ private Messenger mServiceMessenger;
+ private Messenger mReceiveMessenger1;
+ private Messenger mReceiveMessenger2;
+ private int mRequestId;
+ private MediaRouteSelector mSelector;
+
+ private static CountDownLatch sActiveScanCountDownLatch;
+ private static CountDownLatch sPassiveScanCountDownLatch;
+ private static MediaRouteDiscoveryRequest sLastDiscoveryRequest;
+
+ @Before
+ public void setUp() throws Exception {
+ resetActiveAndPassiveScanCountDownLatches();
+ Context context = ApplicationProvider.getApplicationContext();
+ Intent intent =
+ new Intent(context, MediaRouteProviderServiceImpl.class)
+ .setAction(MediaRouteProviderProtocol.SERVICE_INTERFACE);
+ mService = mServiceRule.bindService(intent);
+ mServiceMessenger = new Messenger(mService);
+ mReceiveMessenger1 = new Messenger(new Handler(Looper.getMainLooper()));
+ mReceiveMessenger2 = new Messenger(new Handler(Looper.getMainLooper()));
+ mSelector = new MediaRouteSelector.Builder()
+ .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO).build();
+ registerClient(mReceiveMessenger1);
+ registerClient(mReceiveMessenger2);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ unregisterClient(mReceiveMessenger1);
+ unregisterClient(mReceiveMessenger2);
+ mServiceRule.unbindService();
+ sLastDiscoveryRequest = null;
+ }
+
+ @LargeTest
+ @Test
+ public void testSetEmptyPassiveDiscoveryRequest_shouldNotRequestScan() throws Exception {
+ sendDiscoveryRequest(mReceiveMessenger1,
+ new MediaRouteDiscoveryRequest(MediaRouteSelector.EMPTY, false));
+
+ Thread.sleep(TIME_OUT_MS);
+
+ assertNull(sLastDiscoveryRequest);
+ }
+
+ @LargeTest
+ @Test
+ public void testSetEmptyActiveDiscoveryRequest_shouldRequestScan() throws Exception {
+ resetActiveAndPassiveScanCountDownLatches();
+ sendDiscoveryRequest(mReceiveMessenger1,
+ new MediaRouteDiscoveryRequest(MediaRouteSelector.EMPTY, true));
+
+ assertTrue(sActiveScanCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @LargeTest
+ @Test
+ public void testRequestActiveScan_suppressActiveScanAfter30Seconds() throws Exception {
+ // Request active discovery.
+ resetActiveAndPassiveScanCountDownLatches();
+ sendDiscoveryRequest(mReceiveMessenger1, new MediaRouteDiscoveryRequest(mSelector, true));
+
+ // Active scan should be true.
+ assertTrue(sActiveScanCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+ // Right before active scan duration passes, active scan flag should still be true.
+ resetActiveAndPassiveScanCountDownLatches();
+ assertFalse(sPassiveScanCountDownLatch.await(
+ MAX_ACTIVE_SCAN_DURATION_MS - 1000, TimeUnit.MILLISECONDS));
+
+ // After active scan duration passed, active scan flag should be false.
+ resetActiveAndPassiveScanCountDownLatches();
+ assertTrue(sPassiveScanCountDownLatch.await(1000 + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+ // Request active discovery again.
+ sendDiscoveryRequest(mReceiveMessenger1, new MediaRouteDiscoveryRequest(mSelector, false));
+ resetActiveAndPassiveScanCountDownLatches();
+ sendDiscoveryRequest(mReceiveMessenger1, new MediaRouteDiscoveryRequest(mSelector, true));
+
+ // Active scan should be true.
+ assertTrue(sActiveScanCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+ // Right before active scan duration passes, active scan flag should still be true.
+ resetActiveAndPassiveScanCountDownLatches();
+ assertFalse(sPassiveScanCountDownLatch.await(
+ MAX_ACTIVE_SCAN_DURATION_MS - 1000, TimeUnit.MILLISECONDS));
+
+ // After active scan duration passed, active scan flag should be false.
+ resetActiveAndPassiveScanCountDownLatches();
+ assertTrue(sPassiveScanCountDownLatch.await(1000 + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @LargeTest
+ @Test
+ public void testRequestActiveScanFromMultipleClients_suppressActiveScanAfter30Seconds()
+ throws Exception {
+ // Request active scan from client 1.
+ sendDiscoveryRequest(mReceiveMessenger1, new MediaRouteDiscoveryRequest(mSelector, true));
+
+ // Sleep 10 seconds and request active scan from client 2.
+ Thread.sleep(10000);
+ sendDiscoveryRequest(mReceiveMessenger2, new MediaRouteDiscoveryRequest(mSelector, true));
+
+ // Active scan should be true.
+ assertTrue(sActiveScanCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+ // Right before the last client times out, active scan flag should still be true.
+ resetActiveAndPassiveScanCountDownLatches();
+ assertFalse(sActiveScanCountDownLatch.await(
+ MAX_ACTIVE_SCAN_DURATION_MS - 1000, TimeUnit.MILLISECONDS));
+
+ // Right after the active scan duration passed, active scan flag should be false.
+ resetActiveAndPassiveScanCountDownLatches();
+ assertTrue(sPassiveScanCountDownLatch.await(1000 + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+ private void registerClient(Messenger receiveMessenger) throws Exception {
+ Message msg = Message.obtain();
+ msg.what = MediaRouteProviderProtocol.CLIENT_MSG_REGISTER;
+ msg.arg1 = mRequestId++;
+ msg.arg2 = MediaRouteProviderProtocol.CLIENT_VERSION_CURRENT;
+ msg.replyTo = receiveMessenger;
+
+ mServiceMessenger.send(msg);
+ }
+
+ private void unregisterClient(Messenger receiveMessenger) throws Exception {
+ Message msg = Message.obtain();
+ msg.what = MediaRouteProviderProtocol.CLIENT_MSG_UNREGISTER;
+ msg.replyTo = receiveMessenger;
+
+ mServiceMessenger.send(msg);
+ }
+
+ private void sendDiscoveryRequest(Messenger receiveMessenger,
+ MediaRouteDiscoveryRequest request) throws Exception {
+ Message msg = Message.obtain();
+ msg.what = MediaRouteProviderProtocol.CLIENT_MSG_SET_DISCOVERY_REQUEST;
+ msg.arg1 = mRequestId++;
+ msg.obj = (request != null) ? request.asBundle() : null;
+ msg.replyTo = receiveMessenger;
+
+ mServiceMessenger.send(msg);
+ }
+
+ /** Fake {@link MediaRouteProviderService} implementation. */
+ public static final class MediaRouteProviderServiceImpl extends MediaRouteProviderService {
+ @Override
+ public MediaRouteProvider onCreateMediaRouteProvider() {
+ return new MediaRouteProviderImpl(this);
+ }
+ }
+
+ /** Fake {@link MediaRouteProvider} implementation. */
+ public static class MediaRouteProviderImpl extends MediaRouteProvider {
+ MediaRouteProviderImpl(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest discoveryRequest) {
+ boolean wasActiveScan =
+ (sLastDiscoveryRequest != null) ? sLastDiscoveryRequest.isActiveScan() : false;
+ boolean isActiveScan =
+ (discoveryRequest != null) ? discoveryRequest.isActiveScan() : false;
+ if (wasActiveScan != isActiveScan) {
+ if (isActiveScan) {
+ sActiveScanCountDownLatch.countDown();
+ } else {
+ sPassiveScanCountDownLatch.countDown();
+ }
+ }
+ sLastDiscoveryRequest = discoveryRequest;
+ }
+ }
+
+ private void resetActiveAndPassiveScanCountDownLatches() {
+ sActiveScanCountDownLatch = new CountDownLatch(1);
+ sPassiveScanCountDownLatch = new CountDownLatch(1);
+ }
+}
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
index f64a65b..9f13b0486 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
@@ -54,7 +54,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
public class MediaRouter2Test {
private static final String TAG = "MR2Test";
- private static final int TIMEOUT_MS = 5000;
+ private static final int TIMEOUT_MS = 5_000;
Context mContext;
MediaRouter mRouter;
@@ -113,6 +113,7 @@
public void selectFromMr1AndStopFromSystem_unselect() throws Exception {
CountDownLatch onRouteSelectedLatch = new CountDownLatch(1);
CountDownLatch onRouteUnselectedLatch = new CountDownLatch(1);
+ CountDownLatch onRouteEnabledLatch = new CountDownLatch(1);
String descriptorId = StubMediaRouteProviderService.ROUTE_ID1;
addCallback(new MediaRouter.Callback() {
@@ -133,6 +134,15 @@
onRouteUnselectedLatch.countDown();
}
}
+
+ @Override
+ public void onRouteChanged(MediaRouter router, RouteInfo route) {
+ if (onRouteUnselectedLatch.getCount() == 0
+ && TextUtils.equals(route.getDescriptorId(), descriptorId)
+ && route.isEnabled()) {
+ onRouteEnabledLatch.countDown();
+ }
+ }
});
waitForRoutesAdded();
assertNotNull(mRoutes);
@@ -148,10 +158,14 @@
() -> !mMr2ProviderServiceAdapter.getAllSessionInfo().isEmpty());
//TODO: Find a correct session info
for (RoutingSessionInfo sessionInfo : mMr2ProviderServiceAdapter.getAllSessionInfo()) {
- mMr2ProviderServiceAdapter.onReleaseSession(MediaRoute2ProviderService.REQUEST_ID_NONE,
- sessionInfo.getId());
+ getInstrumentation().runOnMainSync(() ->
+ mMr2ProviderServiceAdapter.onReleaseSession(
+ MediaRoute2ProviderService.REQUEST_ID_NONE,
+ sessionInfo.getId()));
}
assertTrue(onRouteUnselectedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ // Make sure the route is enabled
+ assertTrue(onRouteEnabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
void addCallback(MediaRouter.Callback callback) {
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterActiveScanThrottlingHelperTest.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterActiveScanThrottlingHelperTest.java
new file mode 100644
index 0000000..dc439aa
--- /dev/null
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterActiveScanThrottlingHelperTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2020 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 androidx.mediarouter.media;
+
+import static androidx.mediarouter.media.MediaRouterActiveScanThrottlingHelper.MAX_ACTIVE_SCAN_DURATION_MS;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.SystemClock;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test {@link MediaRouterActiveScanThrottlingHelper}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class MediaRouterActiveScanThrottlingHelperTest {
+ private static final long TIME_OUT_MS = 3000;
+ private CountDownLatch mCountDownLatch;
+ private Runnable mRunnable;
+
+ @Before
+ public void setUp() {
+ resetCountDownLatch();
+ mRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mCountDownLatch.countDown();
+ }
+ };
+ }
+
+ @Test
+ @LargeTest
+ public void testActiveScan_noActiveScan() throws Exception {
+ long currentTime = SystemClock.elapsedRealtime();
+ MediaRouterActiveScanThrottlingHelper helper = new MediaRouterActiveScanThrottlingHelper(
+ mRunnable);
+
+ helper.reset();
+
+ helper.requestActiveScan(false, currentTime);
+ helper.requestActiveScan(false, currentTime);
+ helper.requestActiveScan(false, currentTime);
+
+ assertFalse(helper.finalizeActiveScanAndScheduleSuppressActiveScanRunnable());
+
+ assertFalse(mCountDownLatch.await(
+ MAX_ACTIVE_SCAN_DURATION_MS + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ @LargeTest
+ public void testActiveScan_hasNonExpiredActiveScan() throws Exception {
+ long currentTime = SystemClock.elapsedRealtime();
+ MediaRouterActiveScanThrottlingHelper helper = new MediaRouterActiveScanThrottlingHelper(
+ mRunnable);
+
+ helper.reset();
+
+ helper.requestActiveScan(true, currentTime);
+ helper.requestActiveScan(false, currentTime);
+ helper.requestActiveScan(false, currentTime);
+
+ assertTrue(helper.finalizeActiveScanAndScheduleSuppressActiveScanRunnable());
+
+ assertTrue(mCountDownLatch.await(
+ MAX_ACTIVE_SCAN_DURATION_MS + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ @LargeTest
+ public void testActiveScan_allActiveScanRequestsExpired() throws Exception {
+ long currentTime = SystemClock.elapsedRealtime();
+ MediaRouterActiveScanThrottlingHelper helper =
+ new MediaRouterActiveScanThrottlingHelper(mRunnable);
+
+ helper.reset();
+
+ helper.requestActiveScan(true, currentTime - MAX_ACTIVE_SCAN_DURATION_MS);
+ helper.requestActiveScan(true, currentTime - MAX_ACTIVE_SCAN_DURATION_MS);
+ helper.requestActiveScan(true, currentTime - MAX_ACTIVE_SCAN_DURATION_MS);
+
+ assertFalse(helper.finalizeActiveScanAndScheduleSuppressActiveScanRunnable());
+
+ assertFalse(mCountDownLatch.await(
+ MAX_ACTIVE_SCAN_DURATION_MS + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+
+ @Test
+ @LargeTest
+ public void testActiveScan_allActiveScanRequestsWithMixedTimestamps() throws Exception {
+ long currentTime = SystemClock.elapsedRealtime();
+ MediaRouterActiveScanThrottlingHelper helper =
+ new MediaRouterActiveScanThrottlingHelper(mRunnable);
+
+ helper.reset();
+
+ helper.requestActiveScan(true, currentTime - 2000);
+ helper.requestActiveScan(true, currentTime - 5000);
+ helper.requestActiveScan(true, currentTime - 7000);
+
+ assertTrue(helper.finalizeActiveScanAndScheduleSuppressActiveScanRunnable());
+
+ // Active scan should not be suppressed before the last active scan is in effect.
+ assertFalse(mCountDownLatch.await(MAX_ACTIVE_SCAN_DURATION_MS - 2000 - 1000,
+ TimeUnit.MILLISECONDS));
+
+ // Active scan should be suppressed after the last active scan times out.
+ assertTrue(mCountDownLatch.await(1000 + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ @LargeTest
+ public void testReset_shouldCleanupActiveScanAndSuppressingRunnable() throws Exception {
+ long currentTime = SystemClock.elapsedRealtime();
+ MediaRouterActiveScanThrottlingHelper helper =
+ new MediaRouterActiveScanThrottlingHelper(mRunnable);
+
+ helper.reset();
+
+ helper.requestActiveScan(true, currentTime);
+ helper.requestActiveScan(false, currentTime);
+ helper.requestActiveScan(false, currentTime);
+
+ assertTrue(helper.finalizeActiveScanAndScheduleSuppressActiveScanRunnable());
+
+ helper.reset();
+
+ assertFalse(mCountDownLatch.await(
+ MAX_ACTIVE_SCAN_DURATION_MS + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ assertFalse(helper.finalizeActiveScanAndScheduleSuppressActiveScanRunnable());
+ }
+
+ private void resetCountDownLatch() {
+ mCountDownLatch = new CountDownLatch(1);
+ }
+}
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterTest.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterTest.java
index 9834612..ad9c2b2 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterTest.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterTest.java
@@ -16,6 +16,7 @@
package androidx.mediarouter.media;
+import static androidx.mediarouter.media.MediaRouterActiveScanThrottlingHelper.MAX_ACTIVE_SCAN_DURATION_MS;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -32,6 +33,7 @@
import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
import androidx.test.filters.SmallTest;
import org.junit.After;
@@ -39,6 +41,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/**
* Test {@link MediaRouter}.
*/
@@ -57,15 +62,20 @@
private MediaRouter mRouter;
private MediaSessionCompat mSession;
private MediaSessionCallback mSessionCallback = new MediaSessionCallback();
+ private MediaRouteProviderImpl mProvider;
+ private CountDownLatch mActiveScanCountDownLatch;
+ private CountDownLatch mPassiveScanCountDownLatch;
@Before
public void setUp() throws Exception {
+ resetActiveAndPassiveScanCountDownLatches();
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
mContext = getApplicationContext();
mRouter = MediaRouter.getInstance(mContext);
mSession = new MediaSessionCompat(mContext, SESSION_TAG);
+ mProvider = new MediaRouteProviderImpl(mContext);
}
});
}
@@ -168,6 +178,91 @@
assertEquals(expectedParams, actualParams);
}
+ @Test
+ @LargeTest
+ public void testRegisterActiveScanCallback_suppressActiveScanAfter30Seconds() throws Exception {
+ MediaRouteSelector selector =
+ new MediaRouteSelector.Builder()
+ .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO).build();
+ MediaRouterCallbackImpl callback = new MediaRouterCallbackImpl();
+
+ // Add the provider and callback.
+ resetActiveAndPassiveScanCountDownLatches();
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mRouter.addProvider(mProvider);
+ mRouter.addCallback(selector, callback,
+ MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+ }
+ });
+
+ // Active scan should be true.
+ assertTrue(mActiveScanCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+ // After active scan duration, active scan should be false.
+ resetActiveAndPassiveScanCountDownLatches();
+ assertTrue(mPassiveScanCountDownLatch.await(
+ MAX_ACTIVE_SCAN_DURATION_MS + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+ // Add the same callback again.
+ resetActiveAndPassiveScanCountDownLatches();
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mRouter.addCallback(selector, callback,
+ MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+ }
+ });
+
+ // Active scan should be true.
+ assertTrue(mActiveScanCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+ // After active scan duration, active scan should be false.
+ resetActiveAndPassiveScanCountDownLatches();
+ assertTrue(mPassiveScanCountDownLatch.await(
+ MAX_ACTIVE_SCAN_DURATION_MS + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ @LargeTest
+ public void testRegisterMultipleActiveScanCallbacks_suppressActiveScanAfter30Seconds()
+ throws Exception {
+ MediaRouteSelector selector =
+ new MediaRouteSelector.Builder()
+ .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO).build();
+ MediaRouterCallbackImpl callback1 = new MediaRouterCallbackImpl();
+ MediaRouterCallbackImpl callback2 = new MediaRouterCallbackImpl();
+
+ // Add the provider and the first callback.
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mRouter.addProvider(mProvider);
+ mRouter.addCallback(selector, callback1,
+ MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+ }
+ });
+
+ // Wait for 5 seconds, add the second callback.
+ Thread.sleep(5000);
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mRouter.addCallback(selector, callback2,
+ MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+ }
+ });
+
+ resetActiveAndPassiveScanCountDownLatches();
+ // Wait for active scan duration to nearly end, active scan flag should be true.
+ assertFalse(mPassiveScanCountDownLatch.await(MAX_ACTIVE_SCAN_DURATION_MS - 1000,
+ TimeUnit.MILLISECONDS));
+
+ // Wait until active scan duration ends, active scan flag should be false.
+ assertTrue(mPassiveScanCountDownLatch.await(1000 + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+ }
+
/**
* Asserts that two Bundles are equal.
*/
@@ -206,4 +301,32 @@
}
}
}
+
+ private class MediaRouteProviderImpl extends MediaRouteProvider {
+ private boolean mIsActiveScan;
+
+ MediaRouteProviderImpl(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest discoveryRequest) {
+ if (mIsActiveScan != discoveryRequest.isActiveScan()) {
+ mIsActiveScan = discoveryRequest.isActiveScan();
+ if (mIsActiveScan) {
+ mActiveScanCountDownLatch.countDown();
+ } else {
+ mPassiveScanCountDownLatch.countDown();
+ }
+ }
+ }
+
+ }
+
+ private void resetActiveAndPassiveScanCountDownLatches() {
+ mActiveScanCountDownLatch = new CountDownLatch(1);
+ mPassiveScanCountDownLatch = new CountDownLatch(1);
+ }
+
+ private static class MediaRouterCallbackImpl extends MediaRouter.Callback {}
}
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java
index f742900..401eb08 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java
@@ -18,10 +18,10 @@
import android.content.Context;
import android.content.IntentFilter;
-import android.util.ArrayMap;
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
+import androidx.collection.ArrayMap;
import java.util.ArrayList;
import java.util.List;
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java
index 4b90f65..a279629 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java
@@ -773,8 +773,9 @@
}
if (shouldUnselect) {
+ mController.onUnselect(MediaRouter.UNSELECT_REASON_STOPPED);
+ mController.onRelease();
if ((mFlags & SESSION_FLAG_MR2) == 0) {
- // Let the client release the controller
ClientRecord clientRecord = mClientRecord.get();
if (clientRecord != null) {
RouteController controller = mController;
@@ -782,12 +783,8 @@
controller = ((DynamicGroupRouteControllerProxy) mController)
.mRouteController;
}
- mServiceImpl.requestReleaseController(clientRecord,
- controller, mRouteId);
+ clientRecord.releaseControllerByProvider(controller, mRouteId);
}
- } else {
- mController.onUnselect(MediaRouter.UNSELECT_REASON_STOPPED);
- mController.onRelease();
}
}
mIsReleased = true;
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderProtocol.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderProtocol.java
index 27305d4..d82e4d1 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderProtocol.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderProtocol.java
@@ -236,11 +236,11 @@
public static final int SERVICE_MSG_DYNAMIC_ROUTE_DESCRIPTORS_CHANGED = 7;
/** (service v3) / (client v4)
- * Request to release a route controller. (unsolicited event)
+ * Route controller released by the provider. (unsolicited event)
* - arg1 : reserved(0)
* - arg2 : controllerId
*/
- public static final int SERVICE_MSG_RELEASE_CONTROLLER = 8;
+ public static final int SERVICE_MSG_CONTROLLER_RELEASED = 8;
public static final String SERVICE_DATA_ERROR = "error";
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderService.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderService.java
index 9ff3b77..1261c18 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderService.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderService.java
@@ -43,6 +43,7 @@
import static androidx.mediarouter.media.MediaRouteProviderProtocol.DATA_KEY_GROUP_ROUTE_DESCRIPTOR;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.DATA_KEY_TRANSFERABLE_SECTION_TITLE;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_DATA_ERROR;
+import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_CONTROLLER_RELEASED;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_CONTROL_REQUEST_FAILED;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_DESCRIPTOR_CHANGED;
@@ -51,7 +52,6 @@
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_GENERIC_FAILURE;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_GENERIC_SUCCESS;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_REGISTERED;
-import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_RELEASE_CONTROLLER;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_VERSION_CURRENT;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.isValidRemoteMessenger;
import static androidx.mediarouter.media.MediaRouter.UNSELECT_REASON_UNKNOWN;
@@ -66,10 +66,11 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
+import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-import android.text.TextUtils;
+import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
@@ -87,6 +88,7 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -275,17 +277,17 @@
static void sendGenericFailure(Messenger messenger, int requestId) {
if (requestId != 0) {
- sendReply(messenger, SERVICE_MSG_GENERIC_FAILURE, requestId, 0, null, null);
+ sendMessage(messenger, SERVICE_MSG_GENERIC_FAILURE, requestId, 0, null, null);
}
}
static void sendGenericSuccess(Messenger messenger, int requestId) {
if (requestId != 0) {
- sendReply(messenger, SERVICE_MSG_GENERIC_SUCCESS, requestId, 0, null, null);
+ sendMessage(messenger, SERVICE_MSG_GENERIC_SUCCESS, requestId, 0, null, null);
}
}
- static void sendReply(Messenger messenger, int what,
+ static void sendMessage(Messenger messenger, int what,
int requestId, int arg, Object obj, Bundle data) {
Message msg = Message.obtain();
msg.what = what;
@@ -491,6 +493,14 @@
final ArrayList<ClientRecord> mClients = new ArrayList<ClientRecord>();
MediaRouteDiscoveryRequest mCompositeDiscoveryRequest;
MediaRouteDiscoveryRequest mBaseDiscoveryRequest;
+ long mBaseDiscoveryRequestTimestamp;
+ private final MediaRouterActiveScanThrottlingHelper mActiveScanThrottlingHelper =
+ new MediaRouterActiveScanThrottlingHelper(new Runnable() {
+ @Override
+ public void run() {
+ updateCompositeDiscoveryRequest();
+ }
+ });
MediaRouteProviderServiceImplBase(MediaRouteProviderService service) {
mService = service;
@@ -534,7 +544,7 @@
if (requestId != 0) {
MediaRouteProviderDescriptor descriptor =
mService.getMediaRouteProvider().getDescriptor();
- sendReply(messenger, SERVICE_MSG_REGISTERED,
+ sendMessage(messenger, SERVICE_MSG_REGISTERED,
requestId, SERVICE_VERSION_CURRENT,
createDescriptorBundleForClientVersion(descriptor,
client.mVersion), null);
@@ -604,7 +614,7 @@
+ controllerId
+ ", initialMemberRouteId=" + initialMemberRouteId);
}
- sendReply(messenger, SERVICE_MSG_DYNAMIC_ROUTE_CREATED,
+ sendMessage(messenger, SERVICE_MSG_DYNAMIC_ROUTE_CREATED,
requestId, SERVICE_VERSION_CURRENT,
bundle, null);
return true;
@@ -793,7 +803,7 @@
+ ", data=" + data);
}
if (findClient(messenger) >= 0) {
- sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED,
+ sendMessage(messenger, SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED,
requestId, 0, data, null);
}
}
@@ -810,10 +820,10 @@
if (error != null) {
Bundle bundle = new Bundle();
bundle.putString(SERVICE_DATA_ERROR, error);
- sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
+ sendMessage(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
requestId, 0, data, bundle);
} else {
- sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
+ sendMessage(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
requestId, 0, data, null);
}
}
@@ -853,8 +863,8 @@
final int count = mClients.size();
for (int i = 0; i < count; i++) {
ClientRecord client = mClients.get(i);
- sendReply(client.mMessenger, SERVICE_MSG_DESCRIPTOR_CHANGED, 0, 0,
- createDescriptorBundleForClientVersion(descriptor, client.mVersion), null);
+ sendMessage(client.mMessenger, SERVICE_MSG_DESCRIPTOR_CHANGED, 0, 0,
+ client.createDescriptorBundle(descriptor), null);
if (DEBUG) {
Log.d(TAG, client + ": Sent descriptor change event, descriptor=" + descriptor);
}
@@ -862,8 +872,11 @@
}
boolean setBaseDiscoveryRequest(MediaRouteDiscoveryRequest request) {
- if (!ObjectsCompat.equals(mBaseDiscoveryRequest, request)) {
+ long timestamp = SystemClock.elapsedRealtime();
+ if (!ObjectsCompat.equals(mBaseDiscoveryRequest, request) || request.isActiveScan()) {
mBaseDiscoveryRequest = request;
+ mBaseDiscoveryRequestTimestamp = timestamp;
+
return updateCompositeDiscoveryRequest();
}
return false;
@@ -871,20 +884,24 @@
boolean updateCompositeDiscoveryRequest() {
MediaRouteSelector.Builder selectorBuilder = null;
- boolean activeScan = false;
+ mActiveScanThrottlingHelper.reset();
if (mBaseDiscoveryRequest != null) {
- activeScan = mBaseDiscoveryRequest.isActiveScan();
+ mActiveScanThrottlingHelper.requestActiveScan(
+ mBaseDiscoveryRequest.isActiveScan(),
+ mBaseDiscoveryRequestTimestamp);
selectorBuilder = new MediaRouteSelector.Builder(
mBaseDiscoveryRequest.getSelector());
}
final int count = mClients.size();
for (int i = 0; i < count; i++) {
- MediaRouteDiscoveryRequest request = mClients.get(i).mDiscoveryRequest;
+ ClientRecord clientRecord = mClients.get(i);
+ MediaRouteDiscoveryRequest request = clientRecord.mDiscoveryRequest;
if (request != null
&& (!request.getSelector().isEmpty() || request.isActiveScan())) {
- activeScan |= request.isActiveScan();
+ mActiveScanThrottlingHelper.requestActiveScan(request.isActiveScan(),
+ clientRecord.mDiscoveryRequestTimestamp);
if (selectorBuilder == null) {
selectorBuilder = new MediaRouteSelector.Builder(request.getSelector());
} else {
@@ -893,6 +910,9 @@
}
}
+ boolean activeScan =
+ mActiveScanThrottlingHelper
+ .finalizeActiveScanAndScheduleSuppressActiveScanRunnable();
MediaRouteDiscoveryRequest composite = (selectorBuilder == null) ? null
: new MediaRouteDiscoveryRequest(selectorBuilder.build(), activeScan);
if (!ObjectsCompat.equals(mCompositeDiscoveryRequest, composite)) {
@@ -919,12 +939,12 @@
return -1;
}
- //TODO: Reconsider "ClientRecord" structure
class ClientRecord implements DeathRecipient {
public final Messenger mMessenger;
public final int mVersion;
public final String mPackageName;
public MediaRouteDiscoveryRequest mDiscoveryRequest;
+ public long mDiscoveryRequestTimestamp;
final SparseArray<RouteController> mControllers = new SparseArray<>();
@@ -1023,13 +1043,23 @@
}
public boolean setDiscoveryRequest(MediaRouteDiscoveryRequest request) {
+ long timestamp = SystemClock.elapsedRealtime();
if (!ObjectsCompat.equals(mDiscoveryRequest, request)) {
mDiscoveryRequest = request;
+ mDiscoveryRequestTimestamp = timestamp;
return updateCompositeDiscoveryRequest();
}
+
return false;
}
+ /**
+ * Creates a bundle of the given provider descriptor for this client.
+ */
+ public Bundle createDescriptorBundle(MediaRouteProviderDescriptor descriptor) {
+ return createDescriptorBundleForClientVersion(descriptor, mVersion);
+ }
+
// Runs on a binder thread.
@Override
public void binderDied() {
@@ -1063,7 +1093,7 @@
}
bundle.putParcelableArrayList(DATA_KEY_DYNAMIC_ROUTE_DESCRIPTORS,
dynamicRouteBundles);
- sendReply(mMessenger, SERVICE_MSG_DYNAMIC_ROUTE_DESCRIPTORS_CHANGED,
+ sendMessage(mMessenger, SERVICE_MSG_DYNAMIC_ROUTE_DESCRIPTORS_CHANGED,
0, controllerId, bundle, null);
}
}
@@ -1121,48 +1151,6 @@
mMR2ProviderServiceAdapter.setProviderDescriptor(descriptor);
}
- void requestReleaseController(ClientRecord client,
- RouteController controller, String routeId) {
- if (client.mVersion >= CLIENT_VERSION_4) {
- int controllerId = client.findControllerIdByController(controller);
- if (controllerId < 0) {
- Log.w(TAG, "requestReleaseController: Can't find the controller."
- + " route ID=" + routeId);
- return;
- }
- sendReply(client.mMessenger, SERVICE_MSG_RELEASE_CONTROLLER, 0, controllerId,
- null, null);
- return;
- }
-
- // The below is a workaround to unselect the selected route of previous clients.
- // The logic is based on the behavior that MediaRouter unselects its selected route if
- // the route becomes disabled.
- MediaRouteProviderDescriptor lastDescriptor =
- getService().getMediaRouteProvider().getDescriptor();
- if (lastDescriptor == null) {
- Log.w(TAG, "requestReleaseController: null provider descriptor found. "
- + "It shouldn't happen.");
- return;
- }
-
- List<MediaRouteDescriptor> routes = new ArrayList<>();
- for (MediaRouteDescriptor descriptor : lastDescriptor.getRoutes()) {
- if (TextUtils.equals(descriptor.getId(), routeId)) {
- routes.add(new MediaRouteDescriptor.Builder(descriptor)
- .setEnabled(false).build());
- } else {
- routes.add(descriptor);
- }
- }
-
- MediaRouteProviderDescriptor providerDescriptor =
- new MediaRouteProviderDescriptor.Builder(lastDescriptor)
- .setRoutes(routes).build();
- sendReply(client.mMessenger, SERVICE_MSG_DESCRIPTOR_CHANGED, 0, 0,
- createDescriptorBundleForClientVersion(providerDescriptor, client.mVersion),
- null);
- }
@Override
MediaRouteProviderServiceImplBase.ClientRecord createClientRecord(
@@ -1179,9 +1167,20 @@
class ClientRecord extends MediaRouteProviderServiceImplBase.ClientRecord {
// Maps the route ID to member route controller.
private final Map<String, RouteController> mRouteIdToControllerMap = new ArrayMap<>();
+ private final Handler mClientHandler = new Handler(Looper.getMainLooper());
+
+ // Maps disabled route ID to ID of controllers released by provider.
+ private final Map<String, Integer> mReleasedControllerIds;
+ private static final long DISABLE_ROUTE_FOR_RELEASED_CONTROLLER_TIMEOUT_MS = 5_000;
ClientRecord(Messenger messenger, int version, String packageName) {
super(messenger, version, packageName);
+ // Only required by clients that don't support SERVICE_MSG_CONTROLLER_RELEASED.
+ if (version < CLIENT_VERSION_4) {
+ mReleasedControllerIds = new ArrayMap<>();
+ } else {
+ mReleasedControllerIds = Collections.emptyMap();
+ }
}
@Override
@@ -1233,6 +1232,12 @@
}
}
}
+ for (Map.Entry<String, Integer> entry : mReleasedControllerIds.entrySet()) {
+ if (entry.getValue() == controllerId) {
+ enableRouteForReleasedRouteController(/*routeId=*/entry.getKey());
+ break;
+ }
+ }
return super.releaseRouteController(controllerId);
}
@@ -1248,6 +1253,81 @@
}
}
+ @Override
+ public Bundle createDescriptorBundle(MediaRouteProviderDescriptor descriptor) {
+ if (mReleasedControllerIds.isEmpty()) {
+ return super.createDescriptorBundle(descriptor);
+ }
+
+ List<MediaRouteDescriptor> routes = new ArrayList<>();
+ for (MediaRouteDescriptor routeDescriptor : descriptor.getRoutes()) {
+ if (mReleasedControllerIds.containsKey(routeDescriptor.getId())) {
+ routes.add(new MediaRouteDescriptor.Builder(routeDescriptor)
+ .setEnabled(false).build());
+ } else {
+ routes.add(routeDescriptor);
+ }
+ }
+
+ MediaRouteProviderDescriptor newDescriptor =
+ new MediaRouteProviderDescriptor.Builder(descriptor)
+ .setRoutes(routes).build();
+ return super.createDescriptorBundle(newDescriptor);
+ }
+
+ void releaseControllerByProvider(RouteController controller, String routeId) {
+ int controllerId = findControllerIdByController(controller);
+ releaseRouteController(controllerId);
+
+ // Let the client unselect the corresponding route.
+ if (mVersion >= CLIENT_VERSION_4) {
+ if (controllerId < 0) {
+ Log.w(TAG, "releaseControllerByProvider: Can't find the controller."
+ + " route ID=" + routeId);
+ return;
+ }
+ sendMessage(mMessenger, SERVICE_MSG_CONTROLLER_RELEASED, 0, controllerId,
+ null, null);
+ } else {
+ // Use a workaround for old versions.
+ disableRouteForReleasedRouteController(routeId, controllerId);
+ }
+ }
+
+ /**
+ * Sets the route that corresponds to the given released route controller as disabled
+ * so that media router client unselects the route and releases the route controller
+ * on the client side.
+ * The route becomes enabled when the route controller on the client side is released
+ * or it times out.
+ */
+ private void disableRouteForReleasedRouteController(String routeId, int controllerId) {
+ mReleasedControllerIds.put(routeId, controllerId);
+
+ mClientHandler.postDelayed(() -> enableRouteForReleasedRouteController(routeId),
+ DISABLE_ROUTE_FOR_RELEASED_CONTROLLER_TIMEOUT_MS);
+ sendDescriptor();
+ }
+
+ private void enableRouteForReleasedRouteController(String routeId) {
+ if (mReleasedControllerIds.remove(routeId) == null) {
+ return;
+ }
+ sendDescriptor();
+ }
+
+ /**
+ * Sends the lastly known provider descriptor to the client.
+ */
+ void sendDescriptor() {
+ MediaRouteProviderDescriptor providerDescriptor =
+ getService().getMediaRouteProvider().getDescriptor();
+ if (providerDescriptor != null) {
+ sendMessage(mMessenger, SERVICE_MSG_DESCRIPTOR_CHANGED, 0, 0,
+ createDescriptorBundle(providerDescriptor), null);
+ }
+ }
+
public RouteController findControllerByRouteId(String routeId) {
return mRouteIdToControllerMap.get(routeId);
}
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
index b5dcd5d..0c52eb7 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
@@ -34,6 +34,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemClock;
import android.support.v4.media.session.MediaSessionCompat;
import android.text.TextUtils;
import android.util.Log;
@@ -581,7 +582,9 @@
* The {@link #CALLBACK_FLAG_PERFORM_ACTIVE_SCAN} flag should be used when the
* media route chooser dialog is showing to confirm the presence of available
* routes that the user may connect to. This flag may use substantially more
- * power.
+ * power. Once active scan is requested, it will be effective for 30 seconds and will be
+ * suppressed after the delay. If you need active scan after this duration, you have to add
+ * your callback again with the {@link #CALLBACK_FLAG_PERFORM_ACTIVE_SCAN} flag.
* </p>
*
* <h3>Example</h3>
@@ -677,6 +680,15 @@
record.mFlags = flags;
updateNeeded = true;
}
+ long currentTime = SystemClock.elapsedRealtime();
+ if ((flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
+ // If the flag has active scan, the active scan might be suppressed previously if the
+ // previous change is too long ago. In this case, the discovery request needs to be
+ // updated so that the active scan state can be true again.
+ updateNeeded = true;
+ }
+ record.mTimestamp = currentTime;
+
if (!record.mSelector.contains(selector)) {
record.mSelector = new MediaRouteSelector.Builder(record.mSelector)
.addSelector(selector)
@@ -2276,6 +2288,7 @@
public final Callback mCallback;
public MediaRouteSelector mSelector;
public int mFlags;
+ public long mTimestamp;
public CallbackRecord(MediaRouter router, Callback callback) {
mRouter = router;
@@ -2330,6 +2343,14 @@
private final DisplayManagerCompat mDisplayManager;
final SystemMediaRouteProvider mSystemProvider;
private final boolean mLowRam;
+ private MediaRouterActiveScanThrottlingHelper mActiveScanThrottlingHelper =
+ new MediaRouterActiveScanThrottlingHelper(
+ new Runnable() {
+ @Override
+ public void run() {
+ updateDiscoveryRequest();
+ }
+ });
private MediaRouterParams mRouterParams;
private RegisteredMediaRouteProviderWatcher mRegisteredProviderWatcher;
@@ -2650,8 +2671,8 @@
public void updateDiscoveryRequest() {
// Combine all of the callback selectors and active scan flags.
boolean discover = false;
- boolean activeScan = false;
MediaRouteSelector.Builder builder = new MediaRouteSelector.Builder();
+ mActiveScanThrottlingHelper.reset();
int callbackCount = 0;
for (int i = mRouters.size(); --i >= 0; ) {
@@ -2664,8 +2685,12 @@
for (int j = 0; j < count; j++) {
CallbackRecord callback = router.mCallbackRecords.get(j);
builder.addSelector(callback.mSelector);
- if ((callback.mFlags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
- activeScan = true;
+ boolean callbackRequestingActiveScan =
+ (callback.mFlags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0;
+ mActiveScanThrottlingHelper.requestActiveScan(
+ callbackRequestingActiveScan,
+ callback.mTimestamp);
+ if (callbackRequestingActiveScan) {
discover = true; // perform active scan implies request discovery
}
if ((callback.mFlags & CALLBACK_FLAG_REQUEST_DISCOVERY) != 0) {
@@ -2680,6 +2705,10 @@
}
}
+ boolean activeScan =
+ mActiveScanThrottlingHelper
+ .finalizeActiveScanAndScheduleSuppressActiveScanRunnable();
+
mCallbackCount = callbackCount;
MediaRouteSelector selector = discover ? builder.build() : MediaRouteSelector.EMPTY;
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouterActiveScanThrottlingHelper.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouterActiveScanThrottlingHelper.java
new file mode 100644
index 0000000..4e05ca5
--- /dev/null
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouterActiveScanThrottlingHelper.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2020 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 androidx.mediarouter.media;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+
+/**
+ * Helper class for deciding whether active scan is allowed and when should active scan should be
+ * suppressed.
+ */
+class MediaRouterActiveScanThrottlingHelper {
+ // The constant is package visible for tests can set it to a shorter durationaq.
+ static final long MAX_ACTIVE_SCAN_DURATION_MS = 30000;
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private final Runnable mUpdateDiscoveryRequestRunnable;
+ private long mSuppressActiveScanTimeout;
+ private long mCurrentTime;
+ private boolean mActiveScan;
+
+ MediaRouterActiveScanThrottlingHelper(Runnable updateDiscoveryRequestRunnable) {
+ mUpdateDiscoveryRequestRunnable = updateDiscoveryRequestRunnable;
+ }
+
+ /** Resets the helper as if no active scan is requested. */
+ public void reset() {
+ mSuppressActiveScanTimeout = 0;
+ mActiveScan = false;
+ mCurrentTime = SystemClock.elapsedRealtime();
+ mHandler.removeCallbacks(mUpdateDiscoveryRequestRunnable);
+ }
+
+ /** Add an active scan request. */
+ public void requestActiveScan(boolean activeScanAsRequested, long requestTimestamp) {
+ if (!activeScanAsRequested) {
+ // Active scan not requested.
+ return;
+ }
+
+ if (mCurrentTime - requestTimestamp >= MAX_ACTIVE_SCAN_DURATION_MS) {
+ // Active scan should be suppressed.
+ return;
+ }
+
+ mSuppressActiveScanTimeout =
+ Math.max(
+ mSuppressActiveScanTimeout,
+ requestTimestamp + MAX_ACTIVE_SCAN_DURATION_MS - mCurrentTime);
+
+ mActiveScan = true;
+ }
+
+ /**
+ * Calculate whether active scan is needed based on all active scan requests since last
+ * {@link #reset()} and schedule a runnable to suppress active scan if needed.
+ */
+ public boolean finalizeActiveScanAndScheduleSuppressActiveScanRunnable() {
+ if (mActiveScan && mSuppressActiveScanTimeout > 0) {
+ mHandler.postDelayed(mUpdateDiscoveryRequestRunnable, mSuppressActiveScanTimeout);
+ }
+ return mActiveScan;
+ }
+}
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/RegisteredMediaRouteProvider.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/RegisteredMediaRouteProvider.java
index 1182537..ccd9e0b 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/RegisteredMediaRouteProvider.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/RegisteredMediaRouteProvider.java
@@ -42,6 +42,7 @@
import static androidx.mediarouter.media.MediaRouteProviderProtocol.DATA_KEY_GROUP_ROUTE_DESCRIPTOR;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.DATA_KEY_TRANSFERABLE_SECTION_TITLE;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_DATA_ERROR;
+import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_CONTROLLER_RELEASED;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_CONTROL_REQUEST_FAILED;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_DESCRIPTOR_CHANGED;
@@ -50,7 +51,6 @@
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_GENERIC_FAILURE;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_GENERIC_SUCCESS;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_REGISTERED;
-import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_RELEASE_CONTROLLER;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_VERSION_1;
import static androidx.mediarouter.media.MediaRouteProviderProtocol.isValidRemoteMessenger;
@@ -383,12 +383,13 @@
}
}
- void onConnectionRequestReleaseController(Connection connection, int controllerId) {
+ void onConnectionControllerReleasedByProvider(Connection connection, int controllerId) {
if (mActiveConnection == connection) {
ControllerConnection controller = findControllerById(controllerId);
if (mControllerCallback != null && controller instanceof RouteController) {
- mControllerCallback.onRequestReleaseController(((RouteController) controller));
+ mControllerCallback.onControllerReleasedByProvider(((RouteController) controller));
}
+ onControllerReleased(controller);
}
}
@@ -850,8 +851,8 @@
}
}
- public void onRequestReleaseController(int controllerId) {
- onConnectionRequestReleaseController(this, controllerId);
+ public void onControllerReleasedByProvider(int controllerId) {
+ onConnectionControllerReleasedByProvider(this, controllerId);
}
@Override
@@ -1075,8 +1076,8 @@
}
break;
- case SERVICE_MSG_RELEASE_CONTROLLER:
- connection.onRequestReleaseController(arg /* controllerId */);
+ case SERVICE_MSG_CONTROLLER_RELEASED:
+ connection.onControllerReleasedByProvider(arg /* controllerId */);
break;
}
return false;
@@ -1084,6 +1085,6 @@
}
interface ControllerCallback {
- void onRequestReleaseController(RouteController controller);
+ void onControllerReleasedByProvider(RouteController controller);
}
}
diff --git a/navigation/navigation-ui/api/res-current.txt b/navigation/navigation-ui/api/res-current.txt
index e69de29..e65fdbe 100644
--- a/navigation/navigation-ui/api/res-current.txt
+++ b/navigation/navigation-ui/api/res-current.txt
@@ -0,0 +1,8 @@
+anim nav_default_enter_anim
+anim nav_default_exit_anim
+anim nav_default_pop_enter_anim
+anim nav_default_pop_exit_anim
+animator nav_default_enter_anim
+animator nav_default_exit_anim
+animator nav_default_pop_enter_anim
+animator nav_default_pop_exit_anim
diff --git a/navigation/navigation-ui/src/main/res-public/values/public_anim.xml b/navigation/navigation-ui/src/main/res-public/values/public_anim.xml
deleted file mode 100644
index 267d6b7..0000000
--- a/navigation/navigation-ui/src/main/res-public/values/public_anim.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright 2018 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.
- -->
-
-<!-- Definitions of animations to be exposed as public -->
-<resources>
- <public type="anim" name="nav_default_enter_anim"/>
- <public type="anim" name="nav_default_exit_anim"/>
- <public type="anim" name="nav_default_pop_enter_anim"/>
- <public type="anim" name="nav_default_pop_exit_anim"/>
- <public type="animator" name="nav_default_enter_anim"/>
- <public type="animator" name="nav_default_exit_anim"/>
- <public type="animator" name="nav_default_pop_enter_anim"/>
- <public type="animator" name="nav_default_pop_exit_anim"/>
-</resources>
diff --git a/navigation/navigation-ui/src/main/res/values/public.xml b/navigation/navigation-ui/src/main/res/values/public.xml
new file mode 100644
index 0000000..5613d15
--- /dev/null
+++ b/navigation/navigation-ui/src/main/res/values/public.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <public type="animator" name="nav_default_enter_anim"/>
+ <public type="animator" name="nav_default_exit_anim"/>
+ <public type="animator" name="nav_default_pop_enter_anim"/>
+ <public type="animator" name="nav_default_pop_exit_anim"/>
+ <!-- Deprecated. Use nav_default_enter_animator instead.-->
+ <public type="anim" name="nav_default_enter_anim"/>
+ <!-- Deprecated. Use nav_default_exit_animator instead.-->
+ <public type="anim" name="nav_default_exit_anim"/>
+ <!-- Deprecated. Use nav_default_pop_enter_animator instead.-->
+ <public type="anim" name="nav_default_pop_enter_anim"/>
+ <!-- Deprecated. Use nav_default_pop_exit_animator instead.-->
+ <public type="anim" name="nav_default_pop_exit_anim"/>
+</resources>
diff --git a/paging/common/src/main/kotlin/androidx/paging/PageFetcher.kt b/paging/common/src/main/kotlin/androidx/paging/PageFetcher.kt
index f9e946c..afce683 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PageFetcher.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PageFetcher.kt
@@ -62,29 +62,19 @@
}
.scan(null) { previousGeneration: PageFetcherSnapshot<Key, Value>?,
triggerRemoteRefresh ->
- val pagingSource = pagingSourceFactory()
-
- // Ensure pagingSourceFactory produces a new instance of PagingSource.
- check(pagingSource !== previousGeneration?.pagingSource) {
- """
- An instance of PagingSource was re-used when Pager expected to create a new
- instance. Ensure that the pagingSourceFactory passed to Pager always returns a
- new instance of PagingSource.
- """.trimIndent()
+ var pagingSource = generateNewPagingSource(previousGeneration?.pagingSource)
+ while (pagingSource.invalid) {
+ pagingSource = generateNewPagingSource(previousGeneration?.pagingSource)
}
@OptIn(ExperimentalPagingApi::class)
- val initialKey = previousGeneration?.refreshKeyInfo()
+ val initialKey: Key? = previousGeneration?.refreshKeyInfo()
?.let { pagingSource.getRefreshKey(it) }
?: initialKey
- // Hook up refresh signals from DataSource / PagingSource.
- pagingSource.registerInvalidatedCallback(::invalidate)
- previousGeneration?.pagingSource?.unregisterInvalidatedCallback(::invalidate)
- previousGeneration?.pagingSource?.invalidate() // Note: Invalidate is idempotent.
previousGeneration?.close()
- PageFetcherSnapshot(
+ PageFetcherSnapshot<Key, Value>(
initialKey = initialKey,
pagingSource = pagingSource,
config = config,
@@ -111,6 +101,28 @@
refreshChannel.offer(false)
}
+ private fun generateNewPagingSource(
+ previousPagingSource: PagingSource<Key, Value>?
+ ): PagingSource<Key, Value> {
+ val pagingSource = pagingSourceFactory()
+
+ // Ensure pagingSourceFactory produces a new instance of PagingSource.
+ check(pagingSource !== previousPagingSource) {
+ """
+ An instance of PagingSource was re-used when Pager expected to create a new
+ instance. Ensure that the pagingSourceFactory passed to Pager always returns a
+ new instance of PagingSource.
+ """.trimIndent()
+ }
+
+ // Hook up refresh signals from PagingSource.
+ pagingSource.registerInvalidatedCallback(::invalidate)
+ previousPagingSource?.unregisterInvalidatedCallback(::invalidate)
+ previousPagingSource?.invalidate() // Note: Invalidate is idempotent.
+
+ return pagingSource
+ }
+
inner class PagerUiReceiver<Key : Any, Value : Any> constructor(
private val pageFetcherSnapshot: PageFetcherSnapshot<Key, Value>,
private val retryChannel: SendChannel<Unit>
diff --git a/paging/common/src/test/kotlin/androidx/paging/PageFetcherTest.kt b/paging/common/src/test/kotlin/androidx/paging/PageFetcherTest.kt
index d3e87ce..85855ef 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PageFetcherTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PageFetcherTest.kt
@@ -23,12 +23,14 @@
import androidx.paging.RemoteMediator.InitializeAction.LAUNCH_INITIAL_REFRESH
import androidx.paging.RemoteMediator.InitializeAction.SKIP_INITIAL_REFRESH
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectIndexed
+import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.toList
@@ -395,6 +397,41 @@
assertTrue { job.isCompleted }
}
}
+
+ @ExperimentalStdlibApi
+ @Test
+ fun pagingSourceInvalidBeforeCallbackAdded() = testScope.runBlockingTest {
+ var invalidatesFromAdapter = 0
+ var i = 0
+ var pagingSource: TestPagingSource? = null
+ val pager = Pager(PagingConfig(10)) {
+ i++
+ TestPagingSource().also {
+ if (i == 1) {
+ it.invalidate()
+ }
+
+ advanceUntilIdle()
+ it.registerInvalidatedCallback { invalidatesFromAdapter++ }
+ pagingSource = it
+ }
+ }
+
+ val job = launch {
+ pager.flow.collectLatest { pagingData ->
+ TestPagingDataDiffer<Int>(
+ testScope.coroutineContext[CoroutineDispatcher.Key]!!
+ ).collectFrom(pagingData)
+ }
+ }
+
+ advanceUntilIdle()
+ pagingSource!!.invalidate()
+ advanceUntilIdle()
+
+ assertEquals(1, invalidatesFromAdapter)
+ job.cancel()
+ }
}
internal class FetcherState<T : Any>(
diff --git a/paging/guava/api/current.txt b/paging/guava/api/current.txt
index 1fd7af5..52f6cf3 100644
--- a/paging/guava/api/current.txt
+++ b/paging/guava/api/current.txt
@@ -25,10 +25,10 @@
}
public final class PagingDataFutures {
- method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate);
- method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform);
- method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator);
- method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform, java.util.concurrent.Executor executor);
}
}
diff --git a/paging/guava/api/public_plus_experimental_current.txt b/paging/guava/api/public_plus_experimental_current.txt
index 1fd7af5..52f6cf3 100644
--- a/paging/guava/api/public_plus_experimental_current.txt
+++ b/paging/guava/api/public_plus_experimental_current.txt
@@ -25,10 +25,10 @@
}
public final class PagingDataFutures {
- method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate);
- method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform);
- method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator);
- method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform, java.util.concurrent.Executor executor);
}
}
diff --git a/paging/guava/api/restricted_current.txt b/paging/guava/api/restricted_current.txt
index 1fd7af5..52f6cf3 100644
--- a/paging/guava/api/restricted_current.txt
+++ b/paging/guava/api/restricted_current.txt
@@ -25,10 +25,10 @@
}
public final class PagingDataFutures {
- method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate);
- method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform);
- method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator);
- method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator, java.util.concurrent.Executor executor);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform, java.util.concurrent.Executor executor);
}
}
diff --git a/paging/guava/src/main/java/androidx/paging/ListenableFuturePagingData.kt b/paging/guava/src/main/java/androidx/paging/ListenableFuturePagingData.kt
index 9b92592..9a0d0bd 100644
--- a/paging/guava/src/main/java/androidx/paging/ListenableFuturePagingData.kt
+++ b/paging/guava/src/main/java/androidx/paging/ListenableFuturePagingData.kt
@@ -20,36 +20,63 @@
import androidx.annotation.CheckResult
import com.google.common.util.concurrent.AsyncFunction
+import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.guava.await
+import kotlinx.coroutines.withContext
+import java.util.concurrent.Executor
/**
* Returns a [PagingData] containing the result of applying the given [transform] to each
* element, as it is loaded.
+ *
+ * @param transform [AsyncFunction] to transform an item of type [T] to [R].
+ * @param executor [Executor] to run the [AsyncFunction] in.
*/
@JvmName("map")
@CheckResult
fun <T : Any, R : Any> PagingData<T>.mapAsync(
- transform: AsyncFunction<T, R>
-): PagingData<R> = map { transform.apply(it).await() }
+ transform: AsyncFunction<T, R>,
+ executor: Executor
+): PagingData<R> = map {
+ withContext(executor.asCoroutineDispatcher()) {
+ transform.apply(it).await()
+ }
+}
/**
* Returns a [PagingData] of all elements returned from applying the given [transform] to each
* element, as it is loaded.
+ *
+ * @param transform [AsyncFunction] to transform an item of type [T] a list of items of type [R].
+ * @param executor [Executor] to run the [AsyncFunction] in.
*/
@JvmName("flatMap")
@CheckResult
fun <T : Any, R : Any> PagingData<T>.flatMapAsync(
- transform: AsyncFunction<T, Iterable<R>>
-): PagingData<R> = flatMap { transform.apply(it).await() }
+ transform: AsyncFunction<T, Iterable<R>>,
+ executor: Executor
+): PagingData<R> = flatMap {
+ withContext(executor.asCoroutineDispatcher()) {
+ transform.apply(it).await()
+ }
+}
/**
* Returns a [PagingData] containing only elements matching the given [predicate].
+ *
+ * @param predicate [AsyncFunction] returning `false` for unmatched items which should be filtered.
+ * @param executor [Executor] to run the [AsyncFunction] in.
*/
@JvmName("filter")
@CheckResult
fun <T : Any> PagingData<T>.filterAsync(
- predicate: AsyncFunction<T, Boolean>
-): PagingData<T> = filter { predicate.apply(it).await() }
+ predicate: AsyncFunction<T, Boolean>,
+ executor: Executor
+): PagingData<T> = filter {
+ withContext(executor.asCoroutineDispatcher()) {
+ predicate.apply(it).await()
+ }
+}
/**
* Returns a [PagingData] containing each original element, with an optional separator generated
@@ -58,15 +85,22 @@
* Note that this transform is applied asynchronously, as pages are loaded. Potential separators
* between pages are only computed once both pages are loaded.
*
+ * @param generator [AsyncFunction] used to generate separator between two [AdjacentItems] or the
+ * header or footer if either [AdjacentItems.before] or [AdjacentItems.after] is `null`.
+ * @param executor [Executor] to run the [AsyncFunction] in.
+ *
* @sample androidx.paging.samples.insertSeparatorsFutureSample
* @sample androidx.paging.samples.insertSeparatorsUiModelFutureSample
*/
@JvmName("insertSeparators")
@CheckResult
fun <T : R, R : Any> PagingData<T>.insertSeparatorsAsync(
- generator: AsyncFunction<AdjacentItems<T>, R?>
+ generator: AsyncFunction<AdjacentItems<T>, R?>,
+ executor: Executor
): PagingData<R> = insertSeparators { before, after ->
- generator.apply(AdjacentItems(before, after)).await()
+ withContext(executor.asCoroutineDispatcher()) {
+ generator.apply(AdjacentItems(before, after)).await()
+ }
}
/**
diff --git a/paging/guava/src/test/java/androidx/paging/ListenableFuturePagingDataTest.kt b/paging/guava/src/test/java/androidx/paging/ListenableFuturePagingDataTest.kt
index 497c50f..e7557ab 100644
--- a/paging/guava/src/test/java/androidx/paging/ListenableFuturePagingDataTest.kt
+++ b/paging/guava/src/test/java/androidx/paging/ListenableFuturePagingDataTest.kt
@@ -19,6 +19,7 @@
import com.google.common.util.concurrent.AsyncFunction
import com.google.common.util.concurrent.Futures
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.runBlockingTest
import org.junit.Assert.assertEquals
@@ -38,7 +39,7 @@
fun map() = testDispatcher.runBlockingTest {
val transformed = original.mapAsync(AsyncFunction<String, String> {
Futures.immediateFuture(it + it)
- })
+ }, testDispatcher.asExecutor())
differ.collectFrom(transformed)
assertEquals(listOf("aa", "bb", "cc"), differ.currentList)
}
@@ -47,7 +48,7 @@
fun flatMap() = testDispatcher.runBlockingTest {
val transformed = original.flatMapAsync(AsyncFunction<String, Iterable<String>> {
Futures.immediateFuture(listOf(it!!, it))
- })
+ }, testDispatcher.asExecutor())
differ.collectFrom(transformed)
assertEquals(listOf("a", "a", "b", "b", "c", "c"), differ.currentList)
}
@@ -56,7 +57,7 @@
fun filter() = testDispatcher.runBlockingTest {
val filtered = original.filterAsync(AsyncFunction {
Futures.immediateFuture(it != "b")
- })
+ }, testDispatcher.asExecutor())
differ.collectFrom(filtered)
assertEquals(listOf("a", "c"), differ.currentList)
}
@@ -67,7 +68,8 @@
AsyncFunction<AdjacentItems<String>, String?> {
val (before, after) = it!!
Futures.immediateFuture(if (before == null || after == null) null else "|")
- }
+ },
+ testDispatcher.asExecutor()
)
differ.collectFrom(separated)
assertEquals(listOf("a", "|", "b", "|", "c"), differ.currentList)
diff --git a/paging/integration-tests/testapp/build.gradle b/paging/integration-tests/testapp/build.gradle
index 86a448d..5e16287 100644
--- a/paging/integration-tests/testapp/build.gradle
+++ b/paging/integration-tests/testapp/build.gradle
@@ -29,8 +29,8 @@
dependencies {
implementation("androidx.arch.core:core-runtime:2.1.0")
- implementation("androidx.room:room-ktx:2.2.5")
- implementation("androidx.room:room-rxjava2:2.2.5")
+ implementation(projectOrArtifact(":room:room-ktx"))
+ implementation(projectOrArtifact(":room:room-rxjava2"))
implementation(project(":paging:paging-common-ktx"))
implementation(project(":paging:paging-runtime"))
diff --git a/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsSample.kt b/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsSample.kt
index a9449be..27cfb29 100644
--- a/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsSample.kt
+++ b/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsSample.kt
@@ -114,6 +114,6 @@
null
}
}, executor)
- })
+ }, executor)
}
}
diff --git a/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsUiModelSample.kt b/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsUiModelSample.kt
index 4e07f64..0f90965 100644
--- a/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsUiModelSample.kt
+++ b/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsUiModelSample.kt
@@ -146,6 +146,6 @@
null
}
}, executor)
- })
+ }, executor)
}
}
diff --git a/preference/preference/res/values-bs/strings.xml b/preference/preference/res/values-bs/strings.xml
index 9c72782..f03be77 100644
--- a/preference/preference/res/values-bs/strings.xml
+++ b/preference/preference/res/values-bs/strings.xml
@@ -6,6 +6,6 @@
<string name="expand_button_title" msgid="2427401033573778270">"Napredno"</string>
<string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
<string name="copy" msgid="6083905920877235314">"Kopiraj"</string>
- <string name="preference_copied" msgid="6685851473431805375">"\"<xliff:g id="SUMMARY">%1$s</xliff:g>\" kopirano u međuspremnik."</string>
+ <string name="preference_copied" msgid="6685851473431805375">"\"<xliff:g id="SUMMARY">%1$s</xliff:g>\" kopirano u međumemoriju."</string>
<string name="not_set" msgid="6573031135582639649">"Nije postavljeno"</string>
</resources>
diff --git a/preference/preference/res/values-es-rUS/strings.xml b/preference/preference/res/values-es-rUS/strings.xml
index 1285185..7f45355 100644
--- a/preference/preference/res/values-es-rUS/strings.xml
+++ b/preference/preference/res/values-es-rUS/strings.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="v7_preference_on" msgid="89551595707643515">"ACTIVADA"</string>
+ <string name="v7_preference_on" msgid="89551595707643515">"ACTIVADO"</string>
<string name="v7_preference_off" msgid="3140233346420563315">"DESACTIVADA"</string>
<string name="expand_button_title" msgid="2427401033573778270">"Opciones avanzadas"</string>
<string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
diff --git a/preference/preference/res/values-lt/strings.xml b/preference/preference/res/values-lt/strings.xml
index 682dd1c..cded560 100644
--- a/preference/preference/res/values-lt/strings.xml
+++ b/preference/preference/res/values-lt/strings.xml
@@ -3,7 +3,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="v7_preference_on" msgid="89551595707643515">"ĮJUNGTA"</string>
<string name="v7_preference_off" msgid="3140233346420563315">"IŠJUNGTA"</string>
- <string name="expand_button_title" msgid="2427401033573778270">"Išplėstinė"</string>
+ <string name="expand_button_title" msgid="2427401033573778270">"Išplėstiniai"</string>
<string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
<string name="copy" msgid="6083905920877235314">"Kopijuoti"</string>
<string name="preference_copied" msgid="6685851473431805375">"Suvestinė „<xliff:g id="SUMMARY">%1$s</xliff:g>“ nukopijuota į iškarpinę."</string>
diff --git a/room/common/api/current.txt b/room/common/api/current.txt
index 6fdb17f..3e5fd91 100644
--- a/room/common/api/current.txt
+++ b/room/common/api/current.txt
@@ -60,7 +60,7 @@
method public abstract String tableName() default "";
}
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ForeignKey {
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({}) public @interface ForeignKey {
method public abstract String[] childColumns();
method public abstract boolean deferred() default false;
method public abstract Class<?> entity();
@@ -142,6 +142,9 @@
method public abstract boolean autoGenerate() default false;
}
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface ProvidedTypeConverter {
+ }
+
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface Query {
method public abstract String value();
}
diff --git a/room/common/api/public_plus_experimental_current.txt b/room/common/api/public_plus_experimental_current.txt
index 6fdb17f..3e5fd91 100644
--- a/room/common/api/public_plus_experimental_current.txt
+++ b/room/common/api/public_plus_experimental_current.txt
@@ -60,7 +60,7 @@
method public abstract String tableName() default "";
}
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ForeignKey {
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({}) public @interface ForeignKey {
method public abstract String[] childColumns();
method public abstract boolean deferred() default false;
method public abstract Class<?> entity();
@@ -142,6 +142,9 @@
method public abstract boolean autoGenerate() default false;
}
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface ProvidedTypeConverter {
+ }
+
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface Query {
method public abstract String value();
}
diff --git a/room/common/api/restricted_current.txt b/room/common/api/restricted_current.txt
index a51a804..94d42bd 100644
--- a/room/common/api/restricted_current.txt
+++ b/room/common/api/restricted_current.txt
@@ -60,7 +60,7 @@
method public abstract String tableName() default "";
}
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ForeignKey {
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({}) public @interface ForeignKey {
method public abstract String[] childColumns();
method public abstract boolean deferred() default false;
method public abstract Class<?> entity();
@@ -142,6 +142,9 @@
method public abstract boolean autoGenerate() default false;
}
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface ProvidedTypeConverter {
+ }
+
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface Query {
method public abstract String value();
}
diff --git a/room/common/src/main/java/androidx/room/ForeignKey.java b/room/common/src/main/java/androidx/room/ForeignKey.java
index 0ee68ea..d3c7f5e 100644
--- a/room/common/src/main/java/androidx/room/ForeignKey.java
+++ b/room/common/src/main/java/androidx/room/ForeignKey.java
@@ -19,6 +19,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
/**
* Declares a foreign key on another {@link Entity}.
@@ -45,6 +46,7 @@
* Please refer to the SQLite <a href="https://sqlite.org/foreignkeys.html">foreign keys</a>
* documentation for details.
*/
+@Target({})
@Retention(RetentionPolicy.CLASS)
public @interface ForeignKey {
/**
diff --git a/room/common/src/main/java/androidx/room/ProvidedTypeConverter.java b/room/common/src/main/java/androidx/room/ProvidedTypeConverter.java
new file mode 100644
index 0000000..fa83bdc
--- /dev/null
+++ b/room/common/src/main/java/androidx/room/ProvidedTypeConverter.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2020 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 androidx.room;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a class as a type converter that will be provided to Room at runtime.
+ * If Room uses the annotated type converter class, it will verify that it is provided in the
+ * builder and if not, will throw an exception.
+ * An instance of a class annotated with this annotation has to be provided to Room using
+ * {@code Room.databaseBuilder.addTypeConverter(Object)}
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface ProvidedTypeConverter {
+}
diff --git a/room/common/src/main/java/androidx/room/TypeConverters.java b/room/common/src/main/java/androidx/room/TypeConverters.java
index e68525b..e4c99dd 100644
--- a/room/common/src/main/java/androidx/room/TypeConverters.java
+++ b/room/common/src/main/java/androidx/room/TypeConverters.java
@@ -25,6 +25,11 @@
* Specifies additional type converters that Room can use. The TypeConverter is added to the scope
* of the element so if you put it on a class / interface, all methods / fields in that class will
* be able to use the converters.
+ *
+ * <p>
+ * TypeConverters can only be used to convert columns / fields, hence cannot be used by a method
+ * with a row return value such as DAO methods that query rows.
+ *
* <ul>
* <li>If you put it on a {@link Database}, all Daos and Entities in that database will be able to
* use it.
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSDeclarationExt.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSDeclarationExt.kt
new file mode 100644
index 0000000..77c3509
--- /dev/null
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSDeclarationExt.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 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 androidx.room.compiler.processing.ksp
+
+import org.jetbrains.kotlin.ksp.symbol.KSClassDeclaration
+import org.jetbrains.kotlin.ksp.symbol.KSDeclaration
+
+/**
+ * Finds the class that contains this declaration and throws [IllegalStateException] if it cannot
+ * be found.
+ * @see [findEnclosingAncestorClassDeclaration]
+ */
+internal fun KSDeclaration.requireEnclosingTypeElement(env: KspProcessingEnv): KspTypeElement {
+ return checkNotNull(findEnclosingTypeElement(env)) {
+ "Cannot find required enclosing type for $this"
+ }
+}
+
+/**
+ * Find the class that contains this declaration.
+ *
+ * Node that this is not necessarily the parent declaration. e.g. when a property is declared in
+ * a constructor, its containing type is actual two levels up.
+ */
+internal fun KSDeclaration.findEnclosingTypeElement(env: KspProcessingEnv): KspTypeElement? {
+ return findEnclosingAncestorClassDeclaration()?.let {
+ env.wrapClassDeclaration(it)
+ }
+}
+
+internal fun KSDeclaration.findEnclosingAncestorClassDeclaration(): KSClassDeclaration? {
+ var parent = parentDeclaration
+ while (parent != null && parent !is KSClassDeclaration) {
+ parent = parent.parentDeclaration
+ }
+ return parent as? KSClassDeclaration
+}
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSPropertyDeclarationExt.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSPropertyDeclarationExt.kt
new file mode 100644
index 0000000..15dfd80
--- /dev/null
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSPropertyDeclarationExt.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 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 androidx.room.compiler.processing.ksp
+
+import org.jetbrains.kotlin.ksp.getAllSuperTypes
+import org.jetbrains.kotlin.ksp.symbol.KSClassDeclaration
+import org.jetbrains.kotlin.ksp.symbol.KSName
+import org.jetbrains.kotlin.ksp.symbol.KSPropertyDeclaration
+import org.jetbrains.kotlin.ksp.symbol.KSType
+import org.jetbrains.kotlin.ksp.symbol.KSTypeArgument
+import org.jetbrains.kotlin.ksp.symbol.KSTypeParameter
+
+/**
+ * Returns the type of a property as if it is member of the given [ksType].
+ *
+ * This is a temporary / inefficient implementation until KSP provides the API. It also does not
+ * handle inner classes properly.
+ * TODO: remove once https://github.com/android/kotlin/issues/26 is implemented
+ */
+internal fun KSPropertyDeclaration.typeAsMemberOf(ksType: KSType): KSType {
+ val myType: KSType = checkNotNull(type?.requireType()) {
+ "Cannot find type of Kotlin property: $this"
+ }
+ val parent = checkNotNull(findEnclosingAncestorClassDeclaration()) {
+ "Cannot find containing class for property. $this"
+ }
+ // TODO traverse grandparents if parent is an inner class as TypeArguments might be declared
+ // there as well.
+ val matchingParentType: KSType = (ksType.declaration as? KSClassDeclaration)
+ ?.getAllSuperTypes()
+ ?.firstOrNull {
+ it.starProjection().declaration == parentDeclaration
+ } ?: return myType
+ // create a map of replacements.
+ val replacements = parent.typeParameters.mapIndexed { index, ksTypeParameter ->
+ ksTypeParameter.name to matchingParentType.arguments.getOrNull(index)
+ }.toMap()
+ return myType.replaceFromMap(replacements)
+}
+
+private fun KSTypeArgument.replaceFromMap(arguments: Map<KSName, KSTypeArgument?>): KSTypeArgument {
+ val myTypeDeclaration = type?.resolve()?.declaration
+ if (myTypeDeclaration is KSTypeParameter) {
+ return arguments[myTypeDeclaration.name] ?: this
+ }
+ return this
+}
+
+private fun KSType.replaceFromMap(arguments: Map<KSName, KSTypeArgument?>): KSType {
+ val myDeclaration = this.declaration
+ if (myDeclaration is KSTypeParameter) {
+ return arguments[myDeclaration.name]?.type?.resolve() ?: this
+ }
+ if (this.arguments.isEmpty()) {
+ return this
+ }
+ return replace(this.arguments.map {
+ it.replaceFromMap(arguments)
+ })
+}
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeExt.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeExt.kt
index f0d47c7..7671b04 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeExt.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeExt.kt
@@ -19,16 +19,15 @@
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeName
-import org.jetbrains.kotlin.ksp.symbol.KSClassifierReference
import org.jetbrains.kotlin.ksp.symbol.KSDeclaration
-import org.jetbrains.kotlin.ksp.symbol.KSName
import org.jetbrains.kotlin.ksp.symbol.KSType
+import org.jetbrains.kotlin.ksp.symbol.KSTypeArgument
import org.jetbrains.kotlin.ksp.symbol.KSTypeReference
-internal val ERROR_PACKAGE_NAME = "androidx.room.compiler.processing.kotlin.error"
+internal const val ERROR_PACKAGE_NAME = "androidx.room.compiler.processing.kotlin.error"
// catch-all type name when we cannot resolve to anything.
-internal val UNDEFINED = ClassName.get(ERROR_PACKAGE_NAME, "Undefined")
+internal val ERROR_TYPE_NAME = ClassName.get(ERROR_PACKAGE_NAME, "CannotResolve")
/**
* Turns a KSTypeReference into a TypeName
@@ -39,34 +38,19 @@
*/
internal fun KSTypeReference?.typeName(): TypeName {
return if (this == null) {
- UNDEFINED
+ ERROR_TYPE_NAME
} else {
- resolve()?.typeName() ?: fallbackClassName()
+ requireType().typeName()
}
}
-private fun KSTypeReference.fallbackClassName(): ClassName {
- return (element as? KSClassifierReference)?.let {
- ClassName.bestGuess(it.referencedName())
- } ?: UNDEFINED
-}
-
-private fun KSName.typeName(): ClassName? {
- if (asString().isBlank()) {
- // fallback to reference
- return null
- }
- // TODO KSP currently do not model package names separate from the simple names.
- // see: https://github.com/android/kotlin/issues/23
- val shortNames = getShortName().split(".")
- return ClassName.get(getQualifier(), shortNames.first(), *(shortNames.drop(1).toTypedArray()))
-}
-
-internal fun KSDeclaration.typeName(): ClassName? {
- // if there is no qualified name, it is an error for room
- val qualified = qualifiedName?.asString() ?: return null
+internal fun KSDeclaration.typeName(): ClassName {
+ // if there is no qualified name, it is a resolution error so just return shared instance
+ // KSP may improve that later and if not, we can improve it in Room
+ // TODO: https://issuetracker.google.com/issues/168639183
+ val qualified = qualifiedName?.asString() ?: return ERROR_TYPE_NAME
// get the package name first, it might throw for invalid types, hence we use safeGetPackageName
- val pkg = safeGetPackageName() ?: return null
+ val pkg = getNormalizedPackageName()
// using qualified name and pkg, figure out the short names.
val shortNames = if (pkg == "") {
qualified
@@ -76,12 +60,12 @@
return ClassName.get(pkg, shortNames.first(), *(shortNames.drop(1).toTypedArray()))
}
-internal fun KSType.typeName(): TypeName? {
+internal fun KSType.typeName(): TypeName {
return if (this.arguments.isNotEmpty()) {
val args: Array<TypeName> = this.arguments.map {
it.type.typeName()
}.toTypedArray()
- val className = declaration.typeName() ?: return null
+ val className = declaration.typeName()
ParameterizedTypeName.get(
className,
*args
@@ -92,26 +76,26 @@
}
/**
- * KSDeclaration.packageName might throw for error types.
- * https://github.com/android/kotlin/issues/121
+ * Root package comes as <root> instead of "" so we work around it here.
*/
-internal fun KSDeclaration.safeGetPackageName(): String? {
- return try {
- packageName.asString().let {
- if (it == "<root>") {
- ""
- } else {
- it
- }
+internal fun KSDeclaration.getNormalizedPackageName(): String {
+ return packageName.asString().let {
+ if (it == "<root>") {
+ ""
+ } else {
+ it
}
- } catch (t: Throwable) {
- null
}
}
-// TODO remove after https://github.com/android/kotlin/issues/123
-internal fun KSType?.isAssignableFromWithErrorWorkaround(other: KSType?): Boolean {
- if (other == null || this == null) return false
- if (isError || other.isError) return false
- return isAssignableFrom(other)
+internal fun KSTypeReference.requireType(): KSType {
+ return checkNotNull(resolve()) {
+ "Resolve in type reference should not have returned null, please file a bug. $this"
+ }
}
+
+internal fun KSTypeArgument.requireType(): KSType {
+ return checkNotNull(type?.requireType()) {
+ "KSTypeArgument.type should not have been null, please file a bug. $this"
+ }
+}
\ No newline at end of file
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFieldElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFieldElement.kt
new file mode 100644
index 0000000..d2634bb
--- /dev/null
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFieldElement.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020 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 androidx.room.compiler.processing.ksp
+
+import androidx.room.compiler.processing.XDeclaredType
+import androidx.room.compiler.processing.XFieldElement
+import androidx.room.compiler.processing.XHasModifiers
+import androidx.room.compiler.processing.XType
+import androidx.room.compiler.processing.XTypeElement
+import org.jetbrains.kotlin.ksp.symbol.KSPropertyDeclaration
+
+internal class KspFieldElement(
+ env: KspProcessingEnv,
+ override val declaration: KSPropertyDeclaration,
+ val containing: KspTypeElement
+) : KspElement(env, declaration), XFieldElement, XHasModifiers by KspHasModifiers(declaration) {
+
+ override val equalityItems: Array<out Any?> by lazy {
+ arrayOf(declaration, containing)
+ }
+
+ override val enclosingTypeElement: XTypeElement by lazy {
+ declaration.requireEnclosingTypeElement(env)
+ }
+
+ override val name: String by lazy {
+ declaration.simpleName.asString()
+ }
+
+ override val type: XType by lazy {
+ env.wrap(declaration.typeAsMemberOf(containing.type.ksType))
+ }
+
+ override fun asMemberOf(other: XDeclaredType): XType {
+ if (containing.type.isSameType(other)) {
+ return type
+ }
+ check(other is KspType)
+ val asMember = declaration.typeAsMemberOf(other.ksType)
+ return env.wrap(asMember)
+ }
+}
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt
index bce4dd0..9c2bcb9 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt
@@ -82,7 +82,7 @@
fun wrap(ksType: KSType): KspType {
return KspType(
env = this,
- resolved = ksType)
+ ksType = ksType)
}
fun wrap(ksTypeReference: KSTypeReference): KspType {
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspRawType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspRawType.kt
index 9f5fa90..7dc0ba6 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspRawType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspRawType.kt
@@ -22,20 +22,17 @@
import org.jetbrains.kotlin.ksp.symbol.KSType
internal class KspRawType private constructor(
- private val ksType: KSType?,
+ private val ksType: KSType,
override val typeName: TypeName
) : XRawType {
constructor(original: KspType) : this(
- ksType = original.ksType?.starProjection(),
+ ksType = original.ksType.starProjection(),
typeName = original.typeName.rawTypeName()
)
override fun isAssignableFrom(other: XRawType): Boolean {
check(other is KspRawType)
- return when {
- other.ksType == null || ksType == null -> this == other
- else -> ksType.isAssignableFrom(other.ksType)
- }
+ return ksType.isAssignableFrom(other.ksType)
}
override fun equals(other: Any?): Boolean {
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
index 995fd0e..c83c021 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
@@ -36,72 +36,66 @@
* We don't necessarily have a [KSTypeReference] (e.g. if we are getting it from an element).
* Similarly, we may not be able to get a [KSType] (e.g. if it resolves to error).
*/
-internal class KspType private constructor(
+internal class KspType(
private val env: KspProcessingEnv,
- private val ksTypeReference: KSTypeReference?,
- resolved: KSType?
+ val ksType: KSType
) : XDeclaredType, XEquality {
constructor(env: KspProcessingEnv, ksTypeReference: KSTypeReference) : this(
env = env,
- ksTypeReference = ksTypeReference,
- resolved = null
+ ksType = ksTypeReference.requireType()
)
- constructor(env: KspProcessingEnv, resolved: KSType) : this(
- env = env,
- ksTypeReference = null,
- resolved = resolved
- )
-
- internal val ksType by lazy {
- resolved ?: ksTypeReference?.resolve()
- }
override val rawType by lazy {
KspRawType(this)
}
+
override val typeArguments: List<XType> by lazy {
- // prioritize type reference if it exists as it will have actual types user picked.
- val args = ksTypeReference?.element?.typeArguments
- ?: resolved?.arguments
- ?: emptyList()
- args.map {
- // TODO what if it.type is null?
+ ksType.arguments.map {
env.wrap(it.type!!)
}
}
override val typeName: TypeName by lazy {
- ksType?.typeName() ?: ksTypeReference?.typeName() ?: UNDEFINED
+ ksType.typeName()
}
+
override val nullability by lazy {
- when (ksType?.nullability) {
+ when (ksType.nullability) {
Nullability.NULLABLE -> XNullability.NULLABLE
Nullability.NOT_NULL -> XNullability.NONNULL
else -> XNullability.UNKNOWN
}
}
+ private val _typeElement by lazy {
+ check(ksType.declaration is KSClassDeclaration) { """
+ Unexpected case where ksType's declaration is not a KSClassDeclaration.
+ Please file a bug.
+ """.trimIndent()
+ }
+ env.wrapClassDeclaration(ksType.declaration as KSClassDeclaration)
+ }
+
override fun asTypeElement(): XTypeElement {
- TODO("elements are not implemented yet")
+ return _typeElement
}
override fun isAssignableFrom(other: XType): Boolean {
check(other is KspType)
- return ksType.isAssignableFromWithErrorWorkaround(other.ksType)
+ return ksType.isAssignableFrom(other.ksType)
}
override fun isError(): Boolean {
- return ksType == null || ksType!!.isError
+ return ksType.isError
}
override fun defaultValue(): String {
- val type = ksType ?: return "null"
// NOTE: this does not match the java implementation though it is probably more correct for
// kotlin.
- if (type.nullability == Nullability.NULLABLE) {
+ if (ksType.nullability == Nullability.NULLABLE) {
return "null"
}
val builtIns = env.resolver.builtIns
- return when (type) {
+ return when (ksType) {
builtIns.booleanType -> "false"
builtIns.byteType, builtIns.shortType, builtIns.intType, builtIns.longType, builtIns
.charType -> "0"
@@ -116,23 +110,25 @@
}
override fun isInt(): Boolean {
- return env.commonTypes.nullableInt.isAssignableFromWithErrorWorkaround(ksType)
+ return env.commonTypes.nullableInt.isAssignableFrom(ksType)
}
override fun isLong(): Boolean {
- return env.commonTypes.nullableLong.isAssignableFromWithErrorWorkaround(ksType)
+ return env.commonTypes.nullableLong.isAssignableFrom(ksType)
}
override fun isByte(): Boolean {
- return env.commonTypes.nullableByte.isAssignableFromWithErrorWorkaround(ksType)
+ return env.commonTypes.nullableByte.isAssignableFrom(ksType)
}
override fun isNone(): Boolean {
- return ksType == null
+ // even void is converted to Unit so we don't have none type in KSP
+ // see: KspTypeTest.noneType
+ return false
}
override fun isType(): Boolean {
- return ksType != null && ksType!!.declaration is KSClassDeclaration
+ return ksType.declaration is KSClassDeclaration
}
override fun isTypeOf(other: KClass<*>): Boolean {
@@ -144,7 +140,7 @@
check(other is KspType)
// NOTE: this is inconsistent with java where nullability is ignored.
// it is intentional but might be reversed if it happens to break use cases.
- return ksType != null && ksType == other.ksType
+ return ksType == other.ksType
}
override fun extendsBound(): XType? {
@@ -167,6 +163,6 @@
}
override fun toString(): String {
- return ksType?.toString() ?: ksTypeReference?.toString() ?: super.toString()
+ return ksType.toString()
}
}
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
index 1300ed6..6b74520 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
@@ -17,13 +17,14 @@
package androidx.room.compiler.processing.ksp
import androidx.room.compiler.processing.XConstructorElement
-import androidx.room.compiler.processing.XDeclaredType
import androidx.room.compiler.processing.XFieldElement
import androidx.room.compiler.processing.XHasModifiers
import androidx.room.compiler.processing.XMethodElement
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.XTypeElement
import com.squareup.javapoet.ClassName
+import org.jetbrains.kotlin.ksp.getAllSuperTypes
+import org.jetbrains.kotlin.ksp.getDeclaredProperties
import org.jetbrains.kotlin.ksp.isOpen
import org.jetbrains.kotlin.ksp.symbol.ClassKind
import org.jetbrains.kotlin.ksp.symbol.KSClassDeclaration
@@ -38,16 +39,11 @@
}
override val packageName: String by lazy {
- declaration.safeGetPackageName() ?: ERROR_PACKAGE_NAME
+ declaration.getNormalizedPackageName()
}
override val enclosingTypeElement: XTypeElement? by lazy {
- val parent = declaration.parentDeclaration
- if (parent is KSClassDeclaration) {
- env.wrapClassDeclaration(parent)
- } else {
- null
- }
+ declaration.findEnclosingTypeElement(env)
}
override val equalityItems: Array<out Any?> by lazy {
@@ -55,15 +51,15 @@
}
override val qualifiedName: String by lazy {
- val pkgName = declaration.safeGetPackageName()
- if (pkgName == null || pkgName.isBlank()) {
+ val pkgName = declaration.getNormalizedPackageName()
+ if (pkgName.isBlank()) {
declaration.simpleName.asString()
} else {
"$pkgName.${declaration.simpleName.asString()}"
}
}
- override val type: XDeclaredType by lazy {
+ override val type: KspType by lazy {
env.wrap(declaration.asStarProjectedType())
}
@@ -77,7 +73,35 @@
}
override val className: ClassName by lazy {
- declaration.typeName() ?: ClassName.get(packageName, name)
+ declaration.typeName()
+ }
+
+ private val _declaredFieldsIncludingSupers by lazy {
+ // Read all properties from all supers and select the ones that are not overridden.
+ // TODO: remove once it is implemented in KSP
+ // https://github.com/android/kotlin/issues/133
+ val selection = declaration
+ .getDeclaredProperties()
+ .associateByTo(mutableMapOf()) {
+ it.simpleName
+ }
+ declaration.getAllSuperTypes().map {
+ it.declaration
+ }.filterIsInstance(KSClassDeclaration::class.java)
+ .flatMap {
+ it.getDeclaredProperties()
+ }.forEach {
+ if (!selection.containsKey(it.simpleName)) {
+ selection[it.simpleName] = it
+ }
+ }
+ selection.values.map {
+ KspFieldElement(
+ env = env,
+ declaration = it,
+ containing = this
+ )
+ }
}
override fun isInterface(): Boolean {
@@ -94,7 +118,7 @@
}
override fun getAllFieldsIncludingPrivateSupers(): List<XFieldElement> {
- TODO("Not yet implemented")
+ return _declaredFieldsIncludingSupers
}
override fun findPrimaryConstructor(): XConstructorElement? {
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSProertyDeclarationExtTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSProertyDeclarationExtTest.kt
new file mode 100644
index 0000000..287c7b7
--- /dev/null
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSProertyDeclarationExtTest.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020 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 androidx.room.compiler.processing.ksp
+
+import androidx.room.compiler.processing.util.KotlinTypeNames.INT_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.LIST_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.MAP_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.PAIR_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.STRING_CLASS_NAME
+import androidx.room.compiler.processing.util.Source
+import androidx.room.compiler.processing.util.TestInvocation
+import androidx.room.compiler.processing.util.runKspTest
+import com.google.common.truth.Truth.assertThat
+import com.squareup.javapoet.ParameterizedTypeName
+import org.jetbrains.kotlin.ksp.getDeclaredProperties
+import org.jetbrains.kotlin.ksp.symbol.KSClassDeclaration
+import org.jetbrains.kotlin.ksp.symbol.KSPropertyDeclaration
+import org.junit.Test
+
+class KSProertyDeclarationExtTest {
+ @Test
+ fun asMemberOfInheritance() {
+ val src = Source.kotlin(
+ "Foo.kt", """
+ open class BaseClass<T, R>(val genericProp : T) {
+ val listOfGeneric : List<T> = TODO()
+ val mapOfStringToGeneric2 : Map<String, R> = TODO()
+ val pairOfGenerics : Pair<T, R> = TODO()
+ }
+ class SubClass(x : Int) : BaseClass<Int, List<String>>(x) {
+ val subClassProp : String = "abc"
+ }
+ """.trimIndent()
+ )
+
+ runKspTest(sources = listOf(src), succeed = true) { invocation ->
+ val base = invocation.requireClass("BaseClass")
+ val sub = invocation.requireClass("SubClass").asStarProjectedType()
+ base.requireProperty("genericProp").let { prop ->
+ assertThat(prop.typeAsMemberOf(sub).typeName()).isEqualTo(INT_CLASS_NAME)
+ }
+ base.requireProperty("listOfGeneric").let { prop ->
+ assertThat(prop.typeAsMemberOf(sub).typeName())
+ .isEqualTo(ParameterizedTypeName.get(LIST_CLASS_NAME, INT_CLASS_NAME))
+ }
+
+ val listOfStringsTypeName =
+ ParameterizedTypeName.get(LIST_CLASS_NAME, STRING_CLASS_NAME)
+ base.requireProperty("mapOfStringToGeneric2").let { prop ->
+ assertThat(prop.typeAsMemberOf(sub).typeName())
+ .isEqualTo(
+ ParameterizedTypeName.get(
+ MAP_CLASS_NAME, STRING_CLASS_NAME, listOfStringsTypeName
+ )
+ )
+ }
+
+ base.requireProperty("pairOfGenerics").let { prop ->
+ assertThat(prop.typeAsMemberOf(sub).typeName())
+ .isEqualTo(
+ ParameterizedTypeName.get(
+ PAIR_CLASS_NAME, INT_CLASS_NAME, listOfStringsTypeName
+ )
+ )
+ }
+ }
+ }
+
+ private fun TestInvocation.requireClass(name: String): KSClassDeclaration {
+ val resolver = (processingEnv as KspProcessingEnv).resolver
+ return resolver.requireClass(name)
+ }
+
+ private fun KSClassDeclaration.requireProperty(name: String): KSPropertyDeclaration {
+ return this.getDeclaredProperties().first {
+ it.simpleName.asString() == name
+ }
+ }
+}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSTypeExtTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSTypeExtTest.kt
index 45d3f67..60d9d6b 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSTypeExtTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSTypeExtTest.kt
@@ -119,16 +119,15 @@
}
""".trimIndent()
)
- val doesNotExistTypeName = ClassName.get("", "DoesNotExist")
runTest(subjectSrc, succeed = false) { resolver ->
val subject = resolver.requireClass("Foo")
assertThat(subject.propertyType("errorField").typeName())
- .isEqualTo(doesNotExistTypeName)
+ .isEqualTo(ERROR_TYPE_NAME)
assertThat(subject.propertyType("listOfError").typeName())
.isEqualTo(
ParameterizedTypeName.get(
LIST_TYPE_NAME,
- doesNotExistTypeName
+ ERROR_TYPE_NAME
)
)
assertThat(subject.propertyType("mutableMapOfDontExist").typeName())
@@ -136,7 +135,7 @@
ParameterizedTypeName.get(
MUTABLE_MAP_TYPE_NAME,
STRING_TYPE_NAME,
- doesNotExistTypeName
+ ERROR_TYPE_NAME
)
)
}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFieldElementTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFieldElementTest.kt
new file mode 100644
index 0000000..8960503
--- /dev/null
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFieldElementTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2020 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 androidx.room.compiler.processing.ksp
+
+import androidx.room.compiler.processing.util.KotlinTypeNames.INT_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.LIST_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.STRING_CLASS_NAME
+import androidx.room.compiler.processing.util.Source
+import androidx.room.compiler.processing.util.getField
+import androidx.room.compiler.processing.util.runKspTest
+import com.google.common.truth.Truth.assertThat
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.ParameterizedTypeName
+import org.junit.Test
+
+class KspFieldElementTest {
+ @Test
+ fun simple() {
+ val src = Source.kotlin(
+ "Foo.kt", """
+ class Foo {
+ val intField: Int = 0
+ }
+ """.trimIndent()
+ )
+ runKspTest(sources = listOf(src), succeed = true) { invocation ->
+ val fooElement = invocation.processingEnv.requireTypeElement("Foo")
+ fooElement
+ .getField("intField").let { field ->
+ assertThat(field.name).isEqualTo("intField")
+ assertThat(field.kindName()).isEqualTo("property")
+ assertThat(field.enclosingTypeElement).isEqualTo(fooElement)
+ }
+ }
+ }
+
+ @Test
+ fun asMemberOf() {
+ val src = Source.kotlin(
+ "Foo.kt", """
+ open class Base<T, R> {
+ val t : T = TODO()
+ val listOfR : List<R> = TODO()
+ }
+ class Sub1 : Base<Int, String>()
+ """.trimIndent()
+ )
+ runKspTest(sources = listOf(src), succeed = true) { invocation ->
+ val sub = invocation.processingEnv.requireTypeElement("Sub1")
+ val base = invocation.processingEnv.requireTypeElement("Base")
+ val t = base.getField("t")
+ val listOfR = base.getField("listOfR")
+ assertThat(t.type.typeName).isEqualTo(ClassName.get("Base", "T"))
+ assertThat(listOfR.type.typeName)
+ .isEqualTo(
+ ParameterizedTypeName.get(LIST_CLASS_NAME, ClassName.get("Base", "R"))
+ )
+ assertThat(t.enclosingTypeElement).isEqualTo(base)
+ assertThat(listOfR.enclosingTypeElement).isEqualTo(base)
+ assertThat(t.asMemberOf(sub.type).typeName).isEqualTo(INT_CLASS_NAME)
+ assertThat(listOfR.asMemberOf(sub.type).typeName)
+ .isEqualTo(ParameterizedTypeName.get(LIST_CLASS_NAME, STRING_CLASS_NAME))
+ }
+ }
+}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt
index 7107244..70d6a5e 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt
@@ -17,10 +17,16 @@
package androidx.room.compiler.processing.ksp
import androidx.room.compiler.processing.XTypeElement
+import androidx.room.compiler.processing.util.KotlinTypeNames.INT_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.LIST_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.MUTABLELIST_CLASS_NAME
import androidx.room.compiler.processing.util.Source
+import androidx.room.compiler.processing.util.getAllFieldNames
+import androidx.room.compiler.processing.util.getField
import androidx.room.compiler.processing.util.runKspTest
import com.google.common.truth.Truth.assertThat
import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.ParameterizedTypeName
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -198,4 +204,58 @@
}
}
}
-}
\ No newline at end of file
+
+ @Test
+ fun fieldBasic() {
+ val src = Source.kotlin(
+ "Foo.kt", """
+ open class BaseClass<T>(val genericProp : T)
+ class SubClass(x : Int) : BaseClass<Int>(x) {
+ val subClassProp : String = "abc"
+ }
+ """.trimIndent()
+ )
+ runKspTest(sources = listOf(src), succeed = true) { invocation ->
+ val baseClass = invocation.processingEnv.requireTypeElement("BaseClass")
+ assertThat(baseClass.getAllFieldNames()).containsExactly("genericProp")
+ val subClass = invocation.processingEnv.requireTypeElement("SubClass")
+ assertThat(subClass.getAllFieldNames()).containsExactly("genericProp", "subClassProp")
+ baseClass.getField("genericProp").let { field ->
+ assertThat(field.type.typeName).isEqualTo(ClassName.get("", "BaseClass", "T"))
+ }
+ subClass.getField("genericProp").let { field ->
+ assertThat(field.type.typeName).isEqualTo(ClassName.get("kotlin", "Int"))
+ }
+ }
+ }
+
+ @Test
+ fun fieldsOverride() {
+ val src = Source.kotlin(
+ "Foo.kt", """
+ open class BaseClass(
+ open val value : List<Int>
+ )
+ class SubClass(
+ override val value : MutableList<Int>
+ ) : BaseClass(value)
+ """.trimIndent()
+ )
+ runKspTest(sources = listOf(src), succeed = true) { invocation ->
+ val baseClass = invocation.processingEnv.requireTypeElement("BaseClass")
+ assertThat(baseClass.getAllFieldNames()).containsExactly("value")
+ val subClass = invocation.processingEnv.requireTypeElement("SubClass")
+ assertThat(subClass.getAllFieldNames()).containsExactly("value")
+ assertThat(
+ baseClass.getField("value").type.typeName
+ ).isEqualTo(
+ ParameterizedTypeName.get(LIST_CLASS_NAME, INT_CLASS_NAME)
+ )
+ assertThat(
+ subClass.getField("value").type.typeName
+ ).isEqualTo(
+ ParameterizedTypeName.get(MUTABLELIST_CLASS_NAME, INT_CLASS_NAME)
+ )
+ }
+ }
+}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt
index 241b7b2..e5e3b0a 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt
@@ -23,6 +23,7 @@
import androidx.room.compiler.processing.util.runKspTest
import com.google.common.truth.Truth.assertThat
import com.squareup.javapoet.ClassName
+import org.jetbrains.kotlin.ksp.getClassDeclarationByName
import org.jetbrains.kotlin.ksp.getDeclaredFunctions
import org.jetbrains.kotlin.ksp.symbol.KSPropertyDeclaration
import org.jetbrains.kotlin.ksp.symbol.KSTypeReference
@@ -87,7 +88,8 @@
invocation.requirePropertyType("errorType").let { type ->
assertThat(type.isError()).isTrue()
assertThat(type.typeArguments).isEmpty()
- assertThat(type.typeName).isEqualTo(ClassName.bestGuess("IDontExist"))
+ assertThat(type.typeName).isEqualTo(ERROR_TYPE_NAME)
+ assertThat(type.asTypeElement().className).isEqualTo(ERROR_TYPE_NAME)
}
invocation.requirePropertyType("listOfErrorType").let { type ->
@@ -95,7 +97,7 @@
assertThat(type.typeArguments).hasSize(1)
type.typeArguments.single().let { typeArg ->
assertThat(typeArg.isError()).isTrue()
- assertThat(typeArg.typeName).isEqualTo(ClassName.bestGuess("IDontExist"))
+ assertThat(typeArg.typeName).isEqualTo(ERROR_TYPE_NAME)
}
}
}
@@ -117,6 +119,9 @@
invocation.requirePropertyType("listOfNullableStrings").let { type ->
assertThat(type.nullability).isEqualTo(NONNULL)
assertThat(type.typeArguments).hasSize(1)
+ assertThat(type.asTypeElement().className).isEqualTo(
+ ClassName.get("kotlin.collections", "List")
+ )
type.typeArguments.single().let { typeArg ->
assertThat(typeArg.nullability).isEqualTo(NULLABLE)
assertThat(
@@ -138,6 +143,9 @@
)
).isTrue()
}
+ assertThat(type.asTypeElement().className).isEqualTo(
+ ClassName.get("kotlin.collections", "List")
+ )
}
}
}
@@ -224,6 +232,29 @@
}
@Test
+ fun noneType() {
+ val src = Source.java(
+ "foo.bar.Baz", """
+ package foo.bar;
+ public class Baz {
+ void voidMethod() {
+ }
+ }
+ """.trimIndent()
+ )
+ runKspTest(sources = listOf(src), succeed = true) { invocation ->
+ val resolver = (invocation.processingEnv as KspProcessingEnv).resolver
+ val voidMethod = resolver.getClassDeclarationByName("foo.bar.Baz")!!
+ .getDeclaredFunctions()
+ .first {
+ it.simpleName.asString() == "voidMethod"
+ }
+ val returnType = voidMethod.returnType
+ assertThat(returnType?.typeName()).isEqualTo(ClassName.get("kotlin", "Unit"))
+ }
+ }
+
+ @Test
fun isTypeChecks() {
val src = Source.kotlin(
"foo.kt", """
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/KotlinTypeNames.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/KotlinTypeNames.kt
new file mode 100644
index 0000000..a1b0f22
--- /dev/null
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/KotlinTypeNames.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 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 androidx.room.compiler.processing.util
+
+import com.squareup.javapoet.ClassName
+
+internal object KotlinTypeNames {
+ val INT_CLASS_NAME = ClassName.get("kotlin", "Int")
+ val STRING_CLASS_NAME = ClassName.get("kotlin", "String")
+ val LIST_CLASS_NAME = ClassName.get("kotlin.collections", "List")
+ val MUTABLELIST_CLASS_NAME = ClassName.get("kotlin.collections", "MutableList")
+ val MAP_CLASS_NAME = ClassName.get("kotlin.collections", "Map")
+ val PAIR_CLASS_NAME = ClassName.get(Pair::class.java)
+}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/TestExtensions.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/TestExtensions.kt
index ef3de1a..0e8f322 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/TestExtensions.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/TestExtensions.kt
@@ -19,6 +19,10 @@
import androidx.room.compiler.processing.XExecutableElement
import androidx.room.compiler.processing.XTypeElement
+fun XTypeElement.getAllFieldNames() = getAllFieldsIncludingPrivateSupers().map {
+ it.name
+}
+
fun XTypeElement.getField(name: String) = getAllFieldsIncludingPrivateSupers().first {
it.name == name
}
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/CustomConverterProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/CustomConverterProcessor.kt
index 849710e..1300b96 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/CustomConverterProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/CustomConverterProcessor.kt
@@ -16,6 +16,7 @@
package androidx.room.processor
+import androidx.room.ProvidedTypeConverter
import androidx.room.TypeConverter
import androidx.room.TypeConverters
import androidx.room.compiler.processing.XDeclaredType
@@ -77,21 +78,26 @@
val converterMethods = methods.filter {
it.hasAnnotation(TypeConverter::class)
}
+ val isProvidedConverter = declaredType.asTypeElement()
+ .hasAnnotation(ProvidedTypeConverter::class)
context.checker.check(converterMethods.isNotEmpty(), element, TYPE_CONVERTER_EMPTY_CLASS)
val allStatic = converterMethods.all { it.isStatic() }
val constructors = element.getConstructors()
val isKotlinObjectDeclaration = element.isKotlinObject()
- context.checker.check(
- isKotlinObjectDeclaration || allStatic || constructors.isEmpty() ||
- constructors.any {
- it.parameters.isEmpty()
- }, element, TYPE_CONVERTER_MISSING_NOARG_CONSTRUCTOR
- )
+ if (!isProvidedConverter) {
+ context.checker.check(
+ isKotlinObjectDeclaration || allStatic || constructors.isEmpty() ||
+ constructors.any {
+ it.parameters.isEmpty()
+ }, element, TYPE_CONVERTER_MISSING_NOARG_CONSTRUCTOR
+ )
+ }
return converterMethods.mapNotNull {
processMethod(
container = declaredType,
isContainerKotlinObject = isKotlinObjectDeclaration,
- methodElement = it
+ methodElement = it,
+ isProvidedConverter = isProvidedConverter
)
}
}
@@ -99,7 +105,8 @@
private fun processMethod(
container: XDeclaredType,
methodElement: XMethodElement,
- isContainerKotlinObject: Boolean
+ isContainerKotlinObject: Boolean,
+ isProvidedConverter: Boolean
): CustomTypeConverter? {
val asMember = methodElement.asMemberOf(container)
val returnType = asMember.returnType
@@ -130,7 +137,8 @@
isEnclosingClassKotlinObject = isContainerKotlinObject,
method = methodElement,
from = param,
- to = returnType
+ to = returnType,
+ isProvidedConverter = isProvidedConverter
)
}
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/FtsTableEntityProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/FtsTableEntityProcessor.kt
index c522647..7971604 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/FtsTableEntityProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/FtsTableEntityProcessor.kt
@@ -20,11 +20,11 @@
import androidx.room.Fts4
import androidx.room.FtsOptions.MatchInfo
import androidx.room.FtsOptions.Order
-import androidx.room.parser.FtsVersion
-import androidx.room.parser.SQLTypeAffinity
import androidx.room.compiler.processing.XAnnotationBox
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.XTypeElement
+import androidx.room.parser.FtsVersion
+import androidx.room.parser.SQLTypeAffinity
import androidx.room.processor.EntityProcessor.Companion.extractForeignKeys
import androidx.room.processor.EntityProcessor.Companion.extractIndices
import androidx.room.processor.EntityProcessor.Companion.extractTableName
@@ -99,10 +99,6 @@
context.checker.check(missingNotIndexed.isEmpty(), element,
ProcessorErrors.missingNotIndexedField(missingNotIndexed))
- pojo.fields.filter { it.element.hasAnnotation(androidx.room.ForeignKey::class) }.forEach {
- context.logger.e(ProcessorErrors.INVALID_FOREIGN_KEY_IN_FTS_ENTITY, it.element)
- }
-
context.checker.check(ftsOptions.prefixSizes.all { it > 0 },
element, ProcessorErrors.INVALID_FTS_ENTITY_PREFIX_SIZES)
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index 8cff3a3..1fb9bca 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -294,7 +294,8 @@
val TYPE_CONVERTER_EMPTY_CLASS = "Class is referenced as a converter but it does not have any" +
" converter methods."
val TYPE_CONVERTER_MISSING_NOARG_CONSTRUCTOR = "Classes that are used as TypeConverters must" +
- " have no-argument public constructors."
+ " have no-argument public constructors. Use a ProvidedTypeConverter annotation if you" +
+ " need to take control over creating an instance of a TypeConverter."
val TYPE_CONVERTER_MUST_BE_PUBLIC = "Type converters must be public."
fun duplicateTypeConverters(converters: List<CustomTypeConverter>): String {
@@ -667,8 +668,6 @@
val INVALID_FTS_ENTITY_PREFIX_SIZES = "Prefix sizes to index must non-zero positive values."
- val INVALID_FOREIGN_KEY_IN_FTS_ENTITY = "@ForeignKey is not allowed in an FTS entity fields."
-
val FTS_EXTERNAL_CONTENT_CANNOT_FIND_ENTITY = "Cannot find external content entity class."
fun externalContentNotAnEntity(className: String) = "External content entity referenced in " +
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/types/CustomTypeConverterWrapper.kt b/room/compiler/src/main/kotlin/androidx/room/solver/types/CustomTypeConverterWrapper.kt
index aa1e4e5..6d2b5e9 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/types/CustomTypeConverterWrapper.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/types/CustomTypeConverterWrapper.kt
@@ -16,14 +16,18 @@
package androidx.room.solver.types
+import androidx.room.ProvidedTypeConverter
import androidx.room.ext.L
import androidx.room.ext.N
import androidx.room.ext.T
import androidx.room.solver.CodeGenScope
import androidx.room.vo.CustomTypeConverter
import androidx.room.writer.ClassWriter
+import androidx.room.writer.DaoWriter
import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.CodeBlock
import com.squareup.javapoet.FieldSpec
+import com.squareup.javapoet.MethodSpec
import decapitalize
import java.util.Locale
import javax.lang.model.element.Modifier
@@ -45,13 +49,77 @@
outputVarName, custom.typeName,
custom.methodName, inputVarName)
} else {
- addStatement("$L = $N.$L($L)",
- outputVarName, typeConverter(scope),
+ if (custom.isProvidedConverter) {
+ addStatement("$L = $N().$L($L)",
+ outputVarName, providedTypeConverter(scope),
custom.methodName, inputVarName)
+ } else {
+ addStatement(
+ "$L = $N.$L($L)",
+ outputVarName, typeConverter(scope),
+ custom.methodName, inputVarName
+ )
+ }
}
}
}
+ private fun providedTypeConverter(scope: CodeGenScope): MethodSpec {
+ val className = custom.typeName as ClassName
+ val baseName = className.simpleName().decapitalize(Locale.US)
+
+ val converterClassName = custom.typeName as ClassName
+ scope.writer.addRequiredTypeConverter(converterClassName)
+ val converterField = scope.writer.getOrCreateField(object : ClassWriter.SharedFieldSpec(
+ baseName, custom.typeName
+ ) {
+ override fun getUniqueKey(): String {
+ return "converter_${custom.typeName}"
+ }
+
+ override fun prepare(writer: ClassWriter, builder: FieldSpec.Builder) {
+ builder.addModifiers(Modifier.PRIVATE)
+ }
+ })
+
+ return scope.writer.getOrCreateMethod(object : ClassWriter.SharedMethodSpec(baseName) {
+ override fun getUniqueKey(): String {
+ return "converterMethod_${custom.typeName}"
+ }
+
+ override fun prepare(
+ methodName: String,
+ writer: ClassWriter,
+ builder: MethodSpec.Builder
+ ) {
+ builder.apply {
+ addModifiers(Modifier.PRIVATE)
+ addModifiers(Modifier.SYNCHRONIZED)
+ returns(custom.typeName)
+ addCode(buildConvertMethodBody(writer))
+ }
+ }
+
+ private fun buildConvertMethodBody(
+ writer: ClassWriter
+ ): CodeBlock {
+ val methodScope = CodeGenScope(writer)
+ methodScope.builder().apply {
+ beginControlFlow("if ($N == null)", converterField)
+ addStatement(
+ "$N = $N.getTypeConverter($T.class)",
+ converterField,
+ DaoWriter.dbField,
+ custom.typeName
+ )
+ endControlFlow()
+ addStatement("return $N", converterField)
+ }
+ return methodScope.builder().build()
+ }
+ })
+ }
+
fun typeConverter(scope: CodeGenScope): FieldSpec {
val baseName = (custom.typeName as ClassName).simpleName().decapitalize(Locale.US)
return scope.writer.getOrCreateField(object : ClassWriter.SharedFieldSpec(
@@ -68,3 +136,11 @@
})
}
}
+
+fun ClassWriter.addRequiredTypeConverter(className: ClassName) {
+ this[ProvidedTypeConverter::class] = getRequiredTypeConverters() + setOf(className)
+}
+
+fun ClassWriter.getRequiredTypeConverters(): Set<ClassName> {
+ return this.get<Set<ClassName>>(ProvidedTypeConverter::class) ?: emptySet()
+}
diff --git a/room/compiler/src/main/kotlin/androidx/room/vo/CustomTypeConverter.kt b/room/compiler/src/main/kotlin/androidx/room/vo/CustomTypeConverter.kt
index 96fac0f..dcbcc90 100644
--- a/room/compiler/src/main/kotlin/androidx/room/vo/CustomTypeConverter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/vo/CustomTypeConverter.kt
@@ -28,7 +28,8 @@
val isEnclosingClassKotlinObject: Boolean,
val method: XMethodElement,
val from: XType,
- val to: XType
+ val to: XType,
+ val isProvidedConverter: Boolean
) {
val typeName: TypeName by lazy { enclosingClass.typeName }
val fromTypeName: TypeName by lazy { from.typeName }
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/ClassWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/ClassWriter.kt
index 77976ff..46267c5a 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/ClassWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/ClassWriter.kt
@@ -28,6 +28,7 @@
import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.TypeName
import com.squareup.javapoet.TypeSpec
+import kotlin.reflect.KClass
/**
* Base class for all writers that can produce a class.
@@ -37,9 +38,31 @@
private val sharedMethodSpecs = mutableMapOf<String, MethodSpec>()
private val sharedFieldNames = mutableSetOf<String>()
private val sharedMethodNames = mutableSetOf<String>()
+ private val metadata = mutableMapOf<KClass<*>, Any>()
abstract fun createTypeSpecBuilder(): TypeSpec.Builder
+ /**
+ * Read additional metadata that can be put by sub code generators.
+ *
+ * @see set for more details.
+ */
+ operator fun <T> get(key: KClass<*>): T? {
+ @Suppress("UNCHECKED_CAST")
+ return metadata[key] as? T
+ }
+
+ /**
+ * Add additional metadata to the ClassWriter that can be read back later.
+ * This is useful for additional functionality where a sub code generator needs to bubble up
+ * information to the main ClassWriter without copying it in every intermediate step.
+ *
+ * @see get
+ */
+ operator fun set(key: KClass<*>, value: Any) {
+ metadata[key] = value
+ }
+
fun write(processingEnv: XProcessingEnv) {
val builder = createTypeSpecBuilder()
sharedFieldSpecs.values.forEach { builder.addField(it) }
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
index d4d0af7..30f09b6 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
@@ -27,9 +27,11 @@
import androidx.room.compiler.processing.XMethodElement
import androidx.room.compiler.processing.XProcessingEnv
import androidx.room.compiler.processing.addOriginatingElement
+import androidx.room.ext.CommonTypeNames
import androidx.room.processor.OnConflictProcessor
import androidx.room.solver.CodeGenScope
import androidx.room.solver.KotlinDefaultMethodDelegateBinder
+import androidx.room.solver.types.getRequiredTypeConverters
import androidx.room.vo.Dao
import androidx.room.vo.InsertionMethod
import androidx.room.vo.KotlinDefaultMethodDelegate
@@ -49,11 +51,15 @@
import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeName
import com.squareup.javapoet.TypeSpec
+import com.squareup.javapoet.WildcardTypeName
import stripNonJava
+import java.util.Arrays
+import java.util.Collections
import java.util.Locale
import javax.lang.model.element.Modifier.FINAL
import javax.lang.model.element.Modifier.PRIVATE
import javax.lang.model.element.Modifier.PUBLIC
+import javax.lang.model.element.Modifier.STATIC
/**
* Creates the implementation for a class annotated with Dao.
@@ -67,6 +73,7 @@
private val declaredDao = dao.element.asDeclaredType()
companion object {
+ const val GET_LIST_OF_TYPE_CONVERTERS_METHOD = "getRequiredConverters"
// TODO nothing prevents this from conflicting, we should fix.
val dbField: FieldSpec = FieldSpec
.builder(RoomTypeNames.ROOM_DB, "__db", PRIVATE, FINAL)
@@ -139,10 +146,38 @@
dao.kotlinDefaultMethodDelegates.forEach {
addMethod(createDefaultMethodDelegate(it))
}
+ // keep this the last one to be generated because used custom converters will register
+ // fields with a payload which we collect in dao to report used Type Converters.
+ addMethod(createConverterListMethod())
}
return builder
}
+ private fun createConverterListMethod(): MethodSpec {
+ return MethodSpec.methodBuilder(GET_LIST_OF_TYPE_CONVERTERS_METHOD).apply {
+ addModifiers(STATIC, PUBLIC)
+ returns(
+ ParameterizedTypeName.get(
+ CommonTypeNames.LIST,
+ ParameterizedTypeName.get(
+ ClassName.get(Class::class.java),
+ WildcardTypeName.subtypeOf(Object::class.java)
+ )
+ )
+ )
+ val requiredTypeConverters = getRequiredTypeConverters()
+ if (requiredTypeConverters.isEmpty()) {
+ addStatement("return $T.emptyList()", ClassName.get(Collections::class.java))
+ } else {
+ val placeholders = requiredTypeConverters.joinToString(",") {
+ "$T.class"
+ }
+ val args = arrayOf(ClassName.get(Arrays::class.java)) + requiredTypeConverters
+ addStatement("return $T.asList($placeholders)", *args)
+ }
+ }.build()
+ }
+
private fun createPreparedQueries(
preparedQueries: List<WriteQueryMethod>
): List<PreparedStmtQuery> {
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
index 0ad8ad1..6b07453 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
@@ -30,12 +30,14 @@
import androidx.room.solver.CodeGenScope
import androidx.room.vo.DaoMethod
import androidx.room.vo.Database
+import com.squareup.javapoet.ClassName
import com.squareup.javapoet.FieldSpec
import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.ParameterSpec
import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeName
import com.squareup.javapoet.TypeSpec
+import com.squareup.javapoet.WildcardTypeName
import decapitalize
import stripNonJava
import java.util.Locale
@@ -59,11 +61,63 @@
addMethod(createCreateOpenHelper())
addMethod(createCreateInvalidationTracker())
addMethod(createClearAllTables())
+ addMethod(createCreateTypeConvertersMap())
}
addDaoImpls(builder)
return builder
}
+ private fun createCreateTypeConvertersMap(): MethodSpec {
+ val scope = CodeGenScope(this)
+ return MethodSpec.methodBuilder("getRequiredTypeConverters").apply {
+ addAnnotation(Override::class.java)
+ addModifiers(PROTECTED)
+ returns(ParameterizedTypeName.get(
+ CommonTypeNames.MAP,
+ ParameterizedTypeName.get(
+ ClassName.get(Class::class.java),
+ WildcardTypeName.subtypeOf(Object::class.java)
+ ),
+ ParameterizedTypeName.get(
+ CommonTypeNames.LIST,
+ ParameterizedTypeName.get(
+ ClassName.get(Class::class.java),
+ WildcardTypeName.subtypeOf(Object::class.java)
+ )
+ )
+ ))
+ val typeConvertersVar = scope.getTmpVar("_typeConvertersMap")
+ val typeConvertersTypeName = ParameterizedTypeName.get(
+ ClassName.get(HashMap::class.java),
+ ParameterizedTypeName.get(
+ ClassName.get(Class::class.java),
+ WildcardTypeName.subtypeOf(Object::class.java)
+ ),
+ ParameterizedTypeName.get(
+ ClassName.get(List::class.java),
+ ParameterizedTypeName.get(
+ ClassName.get(Class::class.java),
+ WildcardTypeName.subtypeOf(Object::class.java)
+ )
+ )
+ )
+ addStatement(
+ "final $T $L = new $T()",
+ typeConvertersTypeName,
+ typeConvertersVar,
+ typeConvertersTypeName
+ )
+ database.daoMethods.forEach {
+ addStatement("$L.put($T.class, $T.$L())",
+ typeConvertersVar,
+ it.dao.typeName,
+ it.dao.implTypeName,
+ DaoWriter.GET_LIST_OF_TYPE_CONVERTERS_METHOD)
+ }
+ addStatement("return $L", typeConvertersVar)
+ }.build()
+ }
+
private fun createClearAllTables(): MethodSpec {
val scope = CodeGenScope(this)
return MethodSpec.methodBuilder("clearAllTables").apply {
diff --git a/room/compiler/src/test/data/daoWriter/output/ComplexDao.java b/room/compiler/src/test/data/daoWriter/output/ComplexDao.java
index b5d2256..5de9bb5 100644
--- a/room/compiler/src/test/data/daoWriter/output/ComplexDao.java
+++ b/room/compiler/src/test/data/daoWriter/output/ComplexDao.java
@@ -10,6 +10,7 @@
import androidx.room.util.DBUtil;
import androidx.room.util.StringUtil;
import com.google.common.util.concurrent.ListenableFuture;
+import java.lang.Class;
import java.lang.Exception;
import java.lang.Integer;
import java.lang.Override;
@@ -17,6 +18,7 @@
import java.lang.StringBuilder;
import java.lang.SuppressWarnings;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import javax.annotation.processing.Generated;
@@ -534,4 +536,8 @@
}
}, _statement, true, _cancellationSignal);
}
+
+ public static List<Class<?>> getRequiredConverters() {
+ return Collections.emptyList();
+ }
}
\ No newline at end of file
diff --git a/room/compiler/src/test/data/daoWriter/output/DeletionDao.java b/room/compiler/src/test/data/daoWriter/output/DeletionDao.java
index 713442b..04979c9 100644
--- a/room/compiler/src/test/data/daoWriter/output/DeletionDao.java
+++ b/room/compiler/src/test/data/daoWriter/output/DeletionDao.java
@@ -8,6 +8,7 @@
import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Single;
+import java.lang.Class;
import java.lang.Exception;
import java.lang.Integer;
import java.lang.Override;
@@ -15,6 +16,7 @@
import java.lang.StringBuilder;
import java.lang.SuppressWarnings;
import java.lang.Void;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import javax.annotation.processing.Generated;
@@ -387,4 +389,8 @@
__db.endTransaction();
}
}
-}
+
+ public static List<Class<?>> getRequiredConverters() {
+ return Collections.emptyList();
+ }
+}
\ No newline at end of file
diff --git a/room/compiler/src/test/data/daoWriter/output/UpdateDao.java b/room/compiler/src/test/data/daoWriter/output/UpdateDao.java
index 973ebca..e2e9775 100644
--- a/room/compiler/src/test/data/daoWriter/output/UpdateDao.java
+++ b/room/compiler/src/test/data/daoWriter/output/UpdateDao.java
@@ -7,12 +7,14 @@
import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Single;
+import java.lang.Class;
import java.lang.Exception;
import java.lang.Integer;
import java.lang.Override;
import java.lang.String;
import java.lang.SuppressWarnings;
import java.lang.Void;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import javax.annotation.processing.Generated;
@@ -391,4 +393,8 @@
}
});
}
+
+ public static List<Class<?>> getRequiredConverters() {
+ return Collections.emptyList();
+ }
}
\ No newline at end of file
diff --git a/room/compiler/src/test/data/daoWriter/output/WriterDao.java b/room/compiler/src/test/data/daoWriter/output/WriterDao.java
index a3871dd..3c453dd 100644
--- a/room/compiler/src/test/data/daoWriter/output/WriterDao.java
+++ b/room/compiler/src/test/data/daoWriter/output/WriterDao.java
@@ -19,9 +19,11 @@
import androidx.room.EntityInsertionAdapter;
import androidx.room.RoomDatabase;
import androidx.sqlite.db.SupportSQLiteStatement;
+import java.lang.Class;
import java.lang.Override;
import java.lang.String;
import java.lang.SuppressWarnings;
+import java.util.Collections;
import java.util.List;
import javax.annotation.processing.Generated;
@@ -145,4 +147,8 @@
__db.endTransaction();
}
}
-}
+
+ public static List<Class<?>> getRequiredConverters() {
+ return Collections.emptyList();
+ }
+}
\ No newline at end of file
diff --git a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
index 31ca838..aa123f3 100644
--- a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
+++ b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
@@ -15,11 +15,14 @@
import androidx.sqlite.db.SupportSQLiteOpenHelper;
import androidx.sqlite.db.SupportSQLiteOpenHelper.Callback;
import androidx.sqlite.db.SupportSQLiteOpenHelper.Configuration;
+import java.lang.Class;
import java.lang.Override;
import java.lang.String;
import java.lang.SuppressWarnings;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.annotation.processing.Generated;
@@ -175,6 +178,13 @@
}
@Override
+ protected Map<Class<?>, List<Class<?>>> getRequiredTypeConverters() {
+ final HashMap<Class<?>, List<Class<?>>> _typeConvertersMap = new HashMap<Class<?>, List<Class<?>>>();
+ _typeConvertersMap.put(ComplexDao.class, ComplexDao_Impl.getRequiredConverters());
+ return _typeConvertersMap;
+ }
+
+ @Override
ComplexDao getComplexDao() {
if (_complexDao != null) {
return _complexDao;
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/Fts3TableEntityProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/Fts3TableEntityProcessorTest.kt
index 7147a29..144e045 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/Fts3TableEntityProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/Fts3TableEntityProcessorTest.kt
@@ -141,18 +141,6 @@
}
@Test
- fun badForeignKey() {
- singleEntity("""
- @PrimaryKey
- public int rowid;
- @ForeignKey(entity = MyEntity.class, parentColumns = {}, childColumns = {})
- public int fkId;
- """) { _, _ -> }
- .failsToCompile()
- .withErrorContaining(ProcessorErrors.INVALID_FOREIGN_KEY_IN_FTS_ENTITY)
- }
-
- @Test
fun nonDefaultTokenizer() {
singleEntity("""
@PrimaryKey
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/Fts4TableEntityProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/Fts4TableEntityProcessorTest.kt
index 1888c6f..7686775 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/Fts4TableEntityProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/Fts4TableEntityProcessorTest.kt
@@ -208,18 +208,6 @@
}
@Test
- fun badForeignKey() {
- singleEntity("""
- @PrimaryKey
- public int rowid;
- @ForeignKey(entity = MyEntity.class, parentColumns = {}, childColumns = {})
- public int fkId;
- """) { _, _ -> }
- .failsToCompile()
- .withErrorContaining(ProcessorErrors.INVALID_FOREIGN_KEY_IN_FTS_ENTITY)
- }
-
- @Test
fun nonDefaultTokenizer() {
singleEntity("""
@PrimaryKey
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/ProvidedTypeConverterTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/ProvidedTypeConverterTest.java
new file mode 100644
index 0000000..55537e9
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/ProvidedTypeConverterTest.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2018 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 androidx.room.integration.testapp.test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.room.Database;
+import androidx.room.Entity;
+import androidx.room.Insert;
+import androidx.room.PrimaryKey;
+import androidx.room.ProvidedTypeConverter;
+import androidx.room.Query;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+import androidx.room.TypeConverter;
+import androidx.room.TypeConverters;
+import androidx.room.integration.testapp.TestDatabase;
+import androidx.room.integration.testapp.dao.PetDao;
+import androidx.room.integration.testapp.dao.RobotsDao;
+import androidx.room.integration.testapp.vo.Hivemind;
+import androidx.room.integration.testapp.vo.Pet;
+import androidx.room.integration.testapp.vo.PetWithUser;
+import androidx.room.integration.testapp.vo.Robot;
+import androidx.room.integration.testapp.vo.Toy;
+import androidx.room.integration.testapp.vo.User;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.Objects;
+import java.util.UUID;
+
+@SuppressWarnings("unchecked")
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ProvidedTypeConverterTest {
+
+ @Test
+ public void testProvidedTypeConverter() {
+ Context context = ApplicationProvider.getApplicationContext();
+ TestDatabaseWithConverter db =
+ Room.inMemoryDatabaseBuilder(context, TestDatabaseWithConverter.class)
+ .addTypeConverter(new TimeStampConverter())
+ .addTypeConverter(new UUIDConverter())
+ .build();
+ Pet pet = TestUtil.createPet(3);
+ pet.setName("pet");
+ db.getPetDao().insertOrReplace(pet);
+
+ Robot robot = new Robot(UUID.randomUUID(), UUID.randomUUID());
+ db.getRobotsDao().putRobot(robot);
+ db.close();
+ }
+
+ @Test
+ public void testMissingProvidedTypeConverterInstance() {
+ Context context = ApplicationProvider.getApplicationContext();
+ try {
+ TestDatabaseWithConverter db =
+ Room.inMemoryDatabaseBuilder(context, TestDatabaseWithConverter.class).build();
+ Pet pet = TestUtil.createPet(3);
+ pet.setName("pet");
+ db.getPetDao().insertOrReplace(pet);
+ fail("Show have thrown an IllegalArgumentException");
+ } catch (Throwable throwable) {
+ Assert.assertThat(throwable, instanceOf(IllegalArgumentException.class));
+ }
+ }
+
+ @Test
+ public void testMissingProvidedTypeConverterAnnotation() {
+ Context context = ApplicationProvider.getApplicationContext();
+ try {
+ TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
+ .addTypeConverter(new TimeStampConverter())
+ .build();
+ Pet pet = TestUtil.createPet(3);
+ pet.setName("pet");
+ db.getPetDao().insertOrReplace(pet);
+ fail("Show have thrown an IllegalArgumentException");
+ } catch (Throwable throwable) {
+ Assert.assertThat(throwable, instanceOf(IllegalArgumentException.class));
+ }
+ }
+
+ @Test
+ public void differentSerializerForTheSameClassInDifferentDatabases() {
+ Context context = ApplicationProvider.getApplicationContext();
+ ProvidedTypeConverterNameLastNameDb db1 = Room
+ .inMemoryDatabaseBuilder(context, ProvidedTypeConverterNameLastNameDb.class)
+ .addTypeConverter(new NameLastNameSerializer())
+ .build();
+ ProvidedTypeConverterLastNameNameDb db2 = Room
+ .inMemoryDatabaseBuilder(context, ProvidedTypeConverterLastNameNameDb.class)
+ .addTypeConverter(new LastNameNameSerializer())
+ .build();
+ ProvidedTypeConverterEntity entity1 = new ProvidedTypeConverterEntity(1,
+ new Username("foo1", "bar1"));
+ ProvidedTypeConverterEntity entity2 = new ProvidedTypeConverterEntity(2,
+ new Username("foo2", "bar2"));
+ db1.getDao().insert(entity1);
+ db2.getDao().insert(entity2);
+ assertThat(db1.getDao().get(1)).isEqualTo(entity1);
+ assertThat(db2.getDao().get(2)).isEqualTo(entity2);
+ assertThat(db1.getDao().getRawUsername(1)).isEqualTo("foo1-bar1");
+ assertThat(db2.getDao().getRawUsername(2)).isEqualTo("bar2-foo2");
+ }
+
+ @Database(entities = {Pet.class, Toy.class, User.class, Robot.class, Hivemind.class},
+ views = {PetWithUser.class},
+ version = 1, exportSchema = false)
+ @TypeConverters({TimeStampConverter.class, UUIDConverter.class})
+ abstract static class TestDatabaseWithConverter extends RoomDatabase {
+ public abstract PetDao getPetDao();
+
+ public abstract RobotsDao getRobotsDao();
+ }
+
+
+
+ @Database(entities = {ProvidedTypeConverterEntity.class}, version = 1, exportSchema = false)
+ @TypeConverters(NameLastNameSerializer.class)
+ abstract static class ProvidedTypeConverterNameLastNameDb extends
+ ProvidedTypeConverterEntityDb {
+ }
+
+ @Database(entities = {ProvidedTypeConverterEntity.class}, version = 1, exportSchema = false)
+ @TypeConverters(LastNameNameSerializer.class)
+ abstract static class ProvidedTypeConverterLastNameNameDb extends
+ ProvidedTypeConverterEntityDb {
+ }
+
+ abstract static class ProvidedTypeConverterEntityDb extends RoomDatabase {
+ public abstract ProvidedTypeConverterEntity.Dao getDao();
+ }
+
+ @ProvidedTypeConverter
+ public static class TimeStampConverter {
+ @TypeConverter
+ public Date fromTimestamp(Long value) {
+ return value == null ? null : new Date(value);
+ }
+
+ @TypeConverter
+ public Long dateToTimestamp(Date date) {
+ if (date == null) {
+ return null;
+ } else {
+ return date.getTime();
+ }
+ }
+ }
+
+ @ProvidedTypeConverter
+ public static class UUIDConverter {
+ @TypeConverter
+ public UUID asUuid(byte[] bytes) {
+ ByteBuffer bb = ByteBuffer.wrap(bytes);
+ long firstLong = bb.getLong();
+ long secondLong = bb.getLong();
+ return new UUID(firstLong, secondLong);
+ }
+
+ @TypeConverter
+ public byte[] asBytes(UUID uuid) {
+ ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
+ bb.putLong(uuid.getMostSignificantBits());
+ bb.putLong(uuid.getLeastSignificantBits());
+ return bb.array();
+ }
+ }
+
+ @Entity
+ public static class ProvidedTypeConverterEntity {
+ @PrimaryKey
+ private final int mId;
+ private final Username mUsername;
+
+ public ProvidedTypeConverterEntity(int id, Username username) {
+ mId = id;
+ mUsername = username;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public Username getUsername() {
+ return mUsername;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ProvidedTypeConverterEntity that = (ProvidedTypeConverterEntity) o;
+ return mId == that.mId &&
+ mUsername.equals(that.mUsername);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId, mUsername);
+ }
+
+ @androidx.room.Dao
+ public interface Dao {
+ @Insert
+ void insert(ProvidedTypeConverterEntity entity);
+
+ @Query("SELECT mUsername FROM ProvidedTypeConverterEntity WHERE mId = :id")
+ String getRawUsername(int id);
+
+ @Query("SELECT * FROM ProvidedTypeConverterEntity WHERE mId = :id")
+ ProvidedTypeConverterEntity get(int id);
+ }
+ }
+
+ /**
+ * Class that is serialized differently based on database
+ */
+ public static class Username {
+ @NonNull
+ private final String mName;
+ @NonNull
+ private final String mLastName;
+
+ public Username(@NonNull String name, @NonNull String lastName) {
+ mName = name;
+ mLastName = lastName;
+ }
+
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ @NonNull
+ public String getLastName() {
+ return mLastName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Username username = (Username) o;
+ return mName.equals(username.mName) &&
+ mLastName.equals(username.mLastName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mLastName);
+ }
+ }
+
+ @ProvidedTypeConverter
+ public class NameLastNameSerializer {
+ @TypeConverter
+ public Username fromString(String input) {
+ String[] sections = input.split("-");
+ return new Username(sections[0], sections[1]);
+ }
+
+ @TypeConverter
+ public String toString(Username input) {
+ return input.getName() + "-" + input.getLastName();
+ }
+ }
+
+ @ProvidedTypeConverter
+ public class LastNameNameSerializer {
+ @TypeConverter
+ public Username fromString(String input) {
+ String[] sections = input.split("-");
+ return new Username(sections[1], sections[0]);
+ }
+
+ @TypeConverter
+ public String toString(Username input) {
+ return input.getLastName() + "-" + input.getName();
+ }
+ }
+}
diff --git a/room/runtime/api/current.txt b/room/runtime/api/current.txt
index 6690920..821e4d8 100644
--- a/room/runtime/api/current.txt
+++ b/room/runtime/api/current.txt
@@ -20,6 +20,7 @@
field public final boolean requireMigration;
field public final androidx.sqlite.db.SupportSQLiteOpenHelper.Factory sqliteOpenHelperFactory;
field public final java.util.concurrent.Executor transactionExecutor;
+ field public final java.util.List<java.lang.Object!> typeConverters;
}
public class InvalidationTracker {
@@ -54,6 +55,7 @@
method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
method public java.util.concurrent.Executor getQueryExecutor();
method public java.util.concurrent.Executor getTransactionExecutor();
+ method public <T> T? getTypeConverter(Class<T!>);
method public boolean inTransaction();
method @CallSuper public void init(androidx.room.DatabaseConfiguration);
method protected void internalInitInvalidationTracker(androidx.sqlite.db.SupportSQLiteDatabase);
@@ -70,6 +72,7 @@
public static class RoomDatabase.Builder<T extends androidx.room.RoomDatabase> {
method public androidx.room.RoomDatabase.Builder<T!> addCallback(androidx.room.RoomDatabase.Callback);
method public androidx.room.RoomDatabase.Builder<T!> addMigrations(androidx.room.migration.Migration!...);
+ method public androidx.room.RoomDatabase.Builder<T!> addTypeConverter(Object);
method public androidx.room.RoomDatabase.Builder<T!> allowMainThreadQueries();
method public T build();
method public androidx.room.RoomDatabase.Builder<T!> createFromAsset(String);
diff --git a/room/runtime/api/public_plus_experimental_current.txt b/room/runtime/api/public_plus_experimental_current.txt
index 6690920..af7f13c 100644
--- a/room/runtime/api/public_plus_experimental_current.txt
+++ b/room/runtime/api/public_plus_experimental_current.txt
@@ -20,6 +20,7 @@
field public final boolean requireMigration;
field public final androidx.sqlite.db.SupportSQLiteOpenHelper.Factory sqliteOpenHelperFactory;
field public final java.util.concurrent.Executor transactionExecutor;
+ field public final java.util.List<java.lang.Object!> typeConverters;
}
public class InvalidationTracker {
@@ -53,7 +54,9 @@
method public androidx.room.InvalidationTracker getInvalidationTracker();
method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
method public java.util.concurrent.Executor getQueryExecutor();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected java.util.Map<java.lang.Class<?>!,java.util.List<java.lang.Class<?>!>!> getRequiredTypeConverters();
method public java.util.concurrent.Executor getTransactionExecutor();
+ method public <T> T? getTypeConverter(Class<T!>);
method public boolean inTransaction();
method @CallSuper public void init(androidx.room.DatabaseConfiguration);
method protected void internalInitInvalidationTracker(androidx.sqlite.db.SupportSQLiteDatabase);
@@ -70,6 +73,7 @@
public static class RoomDatabase.Builder<T extends androidx.room.RoomDatabase> {
method public androidx.room.RoomDatabase.Builder<T!> addCallback(androidx.room.RoomDatabase.Callback);
method public androidx.room.RoomDatabase.Builder<T!> addMigrations(androidx.room.migration.Migration!...);
+ method public androidx.room.RoomDatabase.Builder<T!> addTypeConverter(Object);
method public androidx.room.RoomDatabase.Builder<T!> allowMainThreadQueries();
method public T build();
method public androidx.room.RoomDatabase.Builder<T!> createFromAsset(String);
diff --git a/room/runtime/api/restricted_current.txt b/room/runtime/api/restricted_current.txt
index 60e1d8c..a08ad59 100644
--- a/room/runtime/api/restricted_current.txt
+++ b/room/runtime/api/restricted_current.txt
@@ -6,7 +6,8 @@
ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode!, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?);
ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode!, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?);
ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?);
- ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?, androidx.room.RoomDatabase.PrepackagedDatabaseCallback?);
+ ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?, androidx.room.RoomDatabase.PrepackagedDatabaseCallback?);
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?, androidx.room.RoomDatabase.PrepackagedDatabaseCallback?, java.util.List<java.lang.Object!>?);
method public boolean isMigrationRequired(int, int);
method @Deprecated public boolean isMigrationRequiredFrom(int);
field public final boolean allowDestructiveMigrationOnDowngrade;
@@ -25,6 +26,7 @@
field public final boolean requireMigration;
field public final androidx.sqlite.db.SupportSQLiteOpenHelper.Factory sqliteOpenHelperFactory;
field public final java.util.concurrent.Executor transactionExecutor;
+ field public final java.util.List<java.lang.Object!> typeConverters;
}
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class EntityDeletionOrUpdateAdapter<T> extends androidx.room.SharedSQLiteStatement {
@@ -94,6 +96,7 @@
method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
method public java.util.concurrent.Executor getQueryExecutor();
method public java.util.concurrent.Executor getTransactionExecutor();
+ method public <T> T? getTypeConverter(Class<T!>);
method public boolean inTransaction();
method @CallSuper public void init(androidx.room.DatabaseConfiguration);
method protected void internalInitInvalidationTracker(androidx.sqlite.db.SupportSQLiteDatabase);
@@ -112,6 +115,7 @@
public static class RoomDatabase.Builder<T extends androidx.room.RoomDatabase> {
method public androidx.room.RoomDatabase.Builder<T!> addCallback(androidx.room.RoomDatabase.Callback);
method public androidx.room.RoomDatabase.Builder<T!> addMigrations(androidx.room.migration.Migration!...);
+ method public androidx.room.RoomDatabase.Builder<T!> addTypeConverter(Object);
method public androidx.room.RoomDatabase.Builder<T!> allowMainThreadQueries();
method public T build();
method public androidx.room.RoomDatabase.Builder<T!> createFromAsset(String);
diff --git a/room/runtime/src/main/java/androidx/room/DatabaseConfiguration.java b/room/runtime/src/main/java/androidx/room/DatabaseConfiguration.java
index 753ae77..d19c0cb 100644
--- a/room/runtime/src/main/java/androidx/room/DatabaseConfiguration.java
+++ b/room/runtime/src/main/java/androidx/room/DatabaseConfiguration.java
@@ -26,6 +26,7 @@
import java.io.File;
import java.io.InputStream;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
@@ -65,6 +66,9 @@
@Nullable
public final RoomDatabase.PrepackagedDatabaseCallback prepackagedDatabaseCallback;
+ @NonNull
+ public final List<Object> typeConverters;
+
/**
* Whether Room should throw an exception for queries run on the main thread.
*/
@@ -136,7 +140,7 @@
* @deprecated Use {@link #DatabaseConfiguration(Context, String,
* SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
* RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
- * Callable, RoomDatabase.PrepackagedDatabaseCallback)}
+ * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>)}
*
* @param context The application context.
* @param name Name of the database, can be null if it is in memory.
@@ -166,7 +170,7 @@
@Nullable Set<Integer> migrationNotRequiredFrom) {
this(context, name, sqliteOpenHelperFactory, migrationContainer, callbacks,
allowMainThreadQueries, journalMode, queryExecutor, queryExecutor, false,
- requireMigration, false, migrationNotRequiredFrom, null, null, null, null);
+ requireMigration, false, migrationNotRequiredFrom, null, null, null, null, null);
}
/**
@@ -175,7 +179,7 @@
* @deprecated Use {@link #DatabaseConfiguration(Context, String,
* SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
* RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
- * Callable, RoomDatabase.PrepackagedDatabaseCallback)}
+ * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>)}
*
* @param context The application context.
* @param name Name of the database, can be null if it is in memory.
@@ -212,7 +216,7 @@
this(context, name, sqliteOpenHelperFactory, migrationContainer, callbacks,
allowMainThreadQueries, journalMode, queryExecutor, transactionExecutor,
multiInstanceInvalidation, requireMigration, allowDestructiveMigrationOnDowngrade,
- migrationNotRequiredFrom, null, null, null, null);
+ migrationNotRequiredFrom, null, null, null, null, null);
}
/**
@@ -221,7 +225,7 @@
* @deprecated Use {@link #DatabaseConfiguration(Context, String,
* SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
* RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
- * Callable, RoomDatabase.PrepackagedDatabaseCallback)}
+ * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>)}
*
* @param context The application context.
* @param name Name of the database, can be null if it is in memory.
@@ -262,7 +266,7 @@
this(context, name, sqliteOpenHelperFactory, migrationContainer, callbacks,
allowMainThreadQueries, journalMode, queryExecutor, transactionExecutor,
multiInstanceInvalidation, requireMigration, allowDestructiveMigrationOnDowngrade,
- migrationNotRequiredFrom, copyFromAssetPath, copyFromFile, null, null);
+ migrationNotRequiredFrom, copyFromAssetPath, copyFromFile, null, null, null);
}
/**
@@ -271,7 +275,7 @@
* @deprecated Use {@link #DatabaseConfiguration(Context, String,
* SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
* RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
- * Callable, RoomDatabase.PrepackagedDatabaseCallback)}
+ * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>)}
*
* @param context The application context.
* @param name Name of the database, can be null if it is in memory.
@@ -316,7 +320,64 @@
allowMainThreadQueries, journalMode, queryExecutor, transactionExecutor,
multiInstanceInvalidation, requireMigration, allowDestructiveMigrationOnDowngrade,
migrationNotRequiredFrom, copyFromAssetPath, copyFromFile, copyFromInputStream,
- null);
+ null, null);
+ }
+
+ /**
+ * Creates a database configuration with the given values.
+ *
+ * @deprecated Use {@link #DatabaseConfiguration(Context, String,
+ * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
+ * RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
+ * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>)}
+ *
+ * @param context The application context.
+ * @param name Name of the database, can be null if it is in memory.
+ * @param sqliteOpenHelperFactory The open helper factory to use.
+ * @param migrationContainer The migration container for migrations.
+ * @param callbacks The list of callbacks for database events.
+ * @param allowMainThreadQueries Whether to allow main thread reads/writes or not.
+ * @param journalMode The journal mode. This has to be either TRUNCATE or WRITE_AHEAD_LOGGING.
+ * @param queryExecutor The Executor used to execute asynchronous queries.
+ * @param transactionExecutor The Executor used to execute asynchronous transactions.
+ * @param multiInstanceInvalidation True if Room should perform multi-instance invalidation.
+ * @param requireMigration True if Room should require a valid migration if version changes,
+ * @param allowDestructiveMigrationOnDowngrade True if Room should recreate tables if no
+ * migration is supplied during a downgrade.
+ * @param migrationNotRequiredFrom The collection of schema versions from which migrations
+ * aren't required.
+ * @param copyFromAssetPath The assets path to the pre-packaged database.
+ * @param copyFromFile The pre-packaged database file.
+ * @param copyFromInputStream The callable to get the input stream from which a
+ * pre-package database file will be copied from.
+ * @param prepackagedDatabaseCallback The pre-packaged callback.
+ *
+ * @hide
+ */
+ @Deprecated
+ @SuppressLint("LambdaLast")
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+ public DatabaseConfiguration(@NonNull Context context, @Nullable String name,
+ @NonNull SupportSQLiteOpenHelper.Factory sqliteOpenHelperFactory,
+ @NonNull RoomDatabase.MigrationContainer migrationContainer,
+ @Nullable List<RoomDatabase.Callback> callbacks,
+ boolean allowMainThreadQueries,
+ @NonNull RoomDatabase.JournalMode journalMode,
+ @NonNull Executor queryExecutor,
+ @NonNull Executor transactionExecutor,
+ boolean multiInstanceInvalidation,
+ boolean requireMigration,
+ boolean allowDestructiveMigrationOnDowngrade,
+ @Nullable Set<Integer> migrationNotRequiredFrom,
+ @Nullable String copyFromAssetPath,
+ @Nullable File copyFromFile,
+ @Nullable Callable<InputStream> copyFromInputStream,
+ @Nullable RoomDatabase.PrepackagedDatabaseCallback prepackagedDatabaseCallback) {
+ this(context, name, sqliteOpenHelperFactory, migrationContainer, callbacks,
+ allowMainThreadQueries, journalMode, queryExecutor, transactionExecutor,
+ multiInstanceInvalidation, requireMigration, allowDestructiveMigrationOnDowngrade,
+ migrationNotRequiredFrom, copyFromAssetPath, copyFromFile, copyFromInputStream,
+ prepackagedDatabaseCallback, null);
}
/**
@@ -342,6 +403,7 @@
* @param copyFromInputStream The callable to get the input stream from which a
* pre-package database file will be copied from.
* @param prepackagedDatabaseCallback The pre-packaged callback.
+ * @param typeConverters The type converters.
*
* @hide
*/
@@ -362,7 +424,8 @@
@Nullable String copyFromAssetPath,
@Nullable File copyFromFile,
@Nullable Callable<InputStream> copyFromInputStream,
- @Nullable RoomDatabase.PrepackagedDatabaseCallback prepackagedDatabaseCallback) {
+ @Nullable RoomDatabase.PrepackagedDatabaseCallback prepackagedDatabaseCallback,
+ @Nullable List<Object> typeConverters) {
this.sqliteOpenHelperFactory = sqliteOpenHelperFactory;
this.context = context;
this.name = name;
@@ -380,6 +443,7 @@
this.copyFromFile = copyFromFile;
this.copyFromInputStream = copyFromInputStream;
this.prepackagedDatabaseCallback = prepackagedDatabaseCallback;
+ this.typeConverters = typeConverters == null ? Collections.emptyList() : typeConverters;
}
/**
diff --git a/room/runtime/src/main/java/androidx/room/RoomDatabase.java b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
index 97f40e6..88f427d 100644
--- a/room/runtime/src/main/java/androidx/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
@@ -44,6 +44,7 @@
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -141,6 +142,23 @@
return mBackingFieldMap;
}
+ // Updated later to an unmodifiable map when init is called.
+ private final Map<Class<?>, Object> mTypeConverters;
+
+
+ /**
+ * Gets the instance of the given Type Converter.
+ *
+ * @param klass The Type Converter class.
+ * @param <T> The type of the expected Type Converter subclass.
+ * @return An instance of T if it is provided in the builder.
+ */
+ @SuppressWarnings("unchecked")
+ @Nullable
+ public <T> T getTypeConverter(@NonNull Class<T> klass) {
+ return (T) mTypeConverters.get(klass);
+ }
+
/**
* Creates a RoomDatabase.
* <p>
@@ -150,6 +168,7 @@
*/
public RoomDatabase() {
mInvalidationTracker = createInvalidationTracker();
+ mTypeConverters = new HashMap<>();
}
/**
@@ -178,6 +197,45 @@
mInvalidationTracker.startMultiInstanceInvalidation(configuration.context,
configuration.name);
}
+
+ Map<Class<?>, List<Class<?>>> requiredFactories = getRequiredTypeConverters();
+ // indices for each converter on whether it is used or not so that we can throw an exception
+ // if developer provides an unused converter. It is not necessarily an error but likely
+ // to be because why would developer add a converter if it won't be used?
+ BitSet used = new BitSet();
+ for (Map.Entry<Class<?>, List<Class<?>>> entry : requiredFactories.entrySet()) {
+ Class<?> daoName = entry.getKey();
+ for (Class<?> converter : entry.getValue()) {
+ int foundIndex = -1;
+ // traverse provided converters in reverse so that newer one overrides
+ for (int providedIndex = configuration.typeConverters.size() - 1;
+ providedIndex >= 0; providedIndex--) {
+ Object provided = configuration.typeConverters.get(providedIndex);
+ if (converter.isAssignableFrom(provided.getClass())) {
+ foundIndex = providedIndex;
+ used.set(foundIndex);
+ break;
+ }
+ }
+ if (foundIndex < 0) {
+ throw new IllegalArgumentException(
+ "A required type converter (" + converter + ") for"
+ + " " + daoName.getCanonicalName()
+ + " is missing in the database configuration.");
+ }
+ mTypeConverters.put(converter, configuration.typeConverters.get(foundIndex));
+ }
+ }
+ // now, make sure all provided factories are used
+ for (int providedIndex = configuration.typeConverters.size() - 1;
+ providedIndex >= 0; providedIndex--) {
+ if (!used.get(providedIndex)) {
+ Object converter = configuration.typeConverters.get(providedIndex);
+ throw new IllegalArgumentException("Unexpected type converter " + converter + ". "
+ + "Annotate TypeConverter class with @ProvidedTypeConverter annotation "
+ + "or remove this converter from the builder.");
+ }
+ }
}
/**
@@ -212,6 +270,21 @@
protected abstract InvalidationTracker createInvalidationTracker();
/**
+ * Returns a Map of String -> List<Class> where each entry has the `key` as the DAO name
+ * and `value` as the list of type converter classes that are necessary for the database to
+ * function.
+ * <p>
+ * This is implemented by the generated code.
+ *
+ * @return Creates a map that will include all required type converters for this database.
+ */
+ @NonNull
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ protected Map<Class<?>, List<Class<?>>> getRequiredTypeConverters() {
+ return Collections.emptyMap();
+ }
+
+ /**
* Deletes all rows from all the tables that are registered to this database as
* {@link Database#entities()}.
* <p>
@@ -542,6 +615,7 @@
private final Context mContext;
private ArrayList<Callback> mCallbacks;
private PrepackagedDatabaseCallback mPrepackagedDatabaseCallback;
+ private List<Object> mTypeConverters;
/** The Executor used to run database queries. This should be background-threaded. */
private Executor mQueryExecutor;
@@ -1013,6 +1087,22 @@
}
/**
+ * Adds a type converter instance to this database.
+ *
+ * @param typeConverter The converter. It must be an instance of a class annotated with
+ * {@link ProvidedTypeConverter} otherwise Room will throw an exception.
+ * @return This {@link Builder} instance.
+ */
+ @NonNull
+ public Builder<T> addTypeConverter(@NonNull Object typeConverter) {
+ if (mTypeConverters == null) {
+ mTypeConverters = new ArrayList<>();
+ }
+ mTypeConverters.add(typeConverter);
+ return this;
+ }
+
+ /**
* Creates the databases and initializes it.
* <p>
* By default, all RoomDatabases use in memory storage for TEMP tables and enables recursive
@@ -1096,7 +1186,8 @@
mCopyFromAssetPath,
mCopyFromFile,
mCopyFromInputStream,
- mPrepackagedDatabaseCallback);
+ mPrepackagedDatabaseCallback,
+ mTypeConverters);
T db = Room.getGeneratedImplementation(mDatabaseClass, DB_IMPL_SUFFIX);
db.init(configuration);
return db;
diff --git a/room/testing/src/main/java/androidx/room/testing/MigrationTestHelper.java b/room/testing/src/main/java/androidx/room/testing/MigrationTestHelper.java
index baa0f947..fcb1b87 100644
--- a/room/testing/src/main/java/androidx/room/testing/MigrationTestHelper.java
+++ b/room/testing/src/main/java/androidx/room/testing/MigrationTestHelper.java
@@ -168,6 +168,7 @@
null,
null,
null,
+ null,
null);
RoomOpenHelper roomOpenHelper = new RoomOpenHelper(configuration,
new CreatingDelegate(schemaBundle.getDatabase()),
@@ -230,6 +231,7 @@
null,
null,
null,
+ null,
null);
RoomOpenHelper roomOpenHelper = new RoomOpenHelper(configuration,
new MigratingDelegate(schemaBundle.getDatabase(), validateDroppedTables),
diff --git a/settings.gradle b/settings.gradle
index f5c4824..a711917 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -87,6 +87,7 @@
includeProject(":autofill:autofill", "autofill/autofill")
includeProject(":benchmark:benchmark-common", "benchmark/common")
includeProject(":benchmark:benchmark-junit4", "benchmark/junit4")
+includeProject(":benchmark:benchmark-macro", "benchmark/macro")
includeProject(":benchmark:benchmark-benchmark", "benchmark/benchmark")
includeProject(":benchmark:benchmark-gradle-plugin", "benchmark/gradle-plugin")
includeProject(":benchmark:integration-tests:dry-run-benchmark", "benchmark/integration-tests/dry-run-benchmark")
diff --git a/slices/builders/api/current.txt b/slices/builders/api/current.txt
index 3898425..acd2a0f 100644
--- a/slices/builders/api/current.txt
+++ b/slices/builders/api/current.txt
@@ -38,7 +38,7 @@
method public androidx.slice.builders.ListBuilder addSelection(androidx.slice.builders.SelectionBuilder);
method public androidx.slice.builders.ListBuilder setAccentColor(@ColorInt int);
method public androidx.slice.builders.ListBuilder setHeader(androidx.slice.builders.ListBuilder.HeaderBuilder);
- method public androidx.slice.builders.ListBuilder setHostExtra(String, String);
+ method @RequiresApi(21) public androidx.slice.builders.ListBuilder setHostExtras(android.os.PersistableBundle);
method public androidx.slice.builders.ListBuilder setIsError(boolean);
method public androidx.slice.builders.ListBuilder setKeywords(java.util.Set<java.lang.String!>);
method public androidx.slice.builders.ListBuilder setLayoutDirection(int);
diff --git a/slices/builders/api/public_plus_experimental_current.txt b/slices/builders/api/public_plus_experimental_current.txt
index 3898425..acd2a0f 100644
--- a/slices/builders/api/public_plus_experimental_current.txt
+++ b/slices/builders/api/public_plus_experimental_current.txt
@@ -38,7 +38,7 @@
method public androidx.slice.builders.ListBuilder addSelection(androidx.slice.builders.SelectionBuilder);
method public androidx.slice.builders.ListBuilder setAccentColor(@ColorInt int);
method public androidx.slice.builders.ListBuilder setHeader(androidx.slice.builders.ListBuilder.HeaderBuilder);
- method public androidx.slice.builders.ListBuilder setHostExtra(String, String);
+ method @RequiresApi(21) public androidx.slice.builders.ListBuilder setHostExtras(android.os.PersistableBundle);
method public androidx.slice.builders.ListBuilder setIsError(boolean);
method public androidx.slice.builders.ListBuilder setKeywords(java.util.Set<java.lang.String!>);
method public androidx.slice.builders.ListBuilder setLayoutDirection(int);
diff --git a/slices/builders/api/restricted_current.txt b/slices/builders/api/restricted_current.txt
index a658151..f013db9 100644
--- a/slices/builders/api/restricted_current.txt
+++ b/slices/builders/api/restricted_current.txt
@@ -38,7 +38,7 @@
method public androidx.slice.builders.ListBuilder addSelection(androidx.slice.builders.SelectionBuilder);
method public androidx.slice.builders.ListBuilder setAccentColor(@ColorInt int);
method public androidx.slice.builders.ListBuilder setHeader(androidx.slice.builders.ListBuilder.HeaderBuilder);
- method public androidx.slice.builders.ListBuilder setHostExtra(String, String);
+ method @RequiresApi(21) public androidx.slice.builders.ListBuilder setHostExtras(android.os.PersistableBundle);
method public androidx.slice.builders.ListBuilder setIsError(boolean);
method public androidx.slice.builders.ListBuilder setKeywords(java.util.Set<java.lang.String!>);
method public androidx.slice.builders.ListBuilder setLayoutDirection(int);
diff --git a/slices/builders/src/main/java/androidx/slice/builders/ListBuilder.java b/slices/builders/src/main/java/androidx/slice/builders/ListBuilder.java
index a507b3e..c20cac1 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/ListBuilder.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/ListBuilder.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.graphics.drawable.Icon;
import android.net.Uri;
+import android.os.PersistableBundle;
import android.view.View;
import androidx.annotation.ColorInt;
@@ -385,12 +386,12 @@
/**
* Sets additional information to be passed to the host of the slice.
*
- * @param key The name of the extra data
- * @param value The String data value
+ * @param extras The Bundle of extras to add to this slice.
*/
@NonNull
- public ListBuilder setHostExtra(@NonNull String key, @NonNull String value) {
- mImpl.setHostExtra(key, value);
+ @RequiresApi(21)
+ public ListBuilder setHostExtras(@NonNull PersistableBundle extras) {
+ mImpl.setHostExtras(extras);
return this;
}
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java
index 8de49db..a54e56d 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java
@@ -19,6 +19,7 @@
import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import android.app.PendingIntent;
+import android.os.PersistableBundle;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
@@ -146,9 +147,9 @@
/**
* Sets additional information to be passed to the host of the slice.
*
- * @param key The name of the extra data
- * @param value The String data value
+ * @param extras The Bundle of extras to add to this slice.
*/
- void setHostExtra(@NonNull String key, @NonNull String value);
+ @RequiresApi(21)
+ void setHostExtras(@NonNull PersistableBundle extras);
}
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java
index f41ab33..d008227 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java
@@ -32,6 +32,7 @@
import android.app.PendingIntent;
import android.os.Bundle;
+import android.os.PersistableBundle;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
@@ -243,11 +244,17 @@
}
@Override
- public void setHostExtra(@NonNull String key, @NonNull String value) {
- if (mHostExtras == null) {
- mHostExtras = new Bundle();
+ @RequiresApi(21)
+ public void setHostExtras(@NonNull PersistableBundle extras) {
+ mHostExtras = ConvertPersistableBundleApi21Impl.toBundle(extras);
+ }
+
+ @RequiresApi(21)
+ private static class ConvertPersistableBundleApi21Impl {
+ private ConvertPersistableBundleApi21Impl() {}
+ static Bundle toBundle(@NonNull PersistableBundle extras) {
+ return new Bundle(extras);
}
- mHostExtras.putString(key, value);
}
/**
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java
index a4b5984..835b0ac 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java
@@ -51,6 +51,7 @@
import android.app.PendingIntent;
import android.net.Uri;
import android.os.Bundle;
+import android.os.PersistableBundle;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
@@ -306,11 +307,17 @@
}
@Override
- public void setHostExtra(@NonNull String key, @NonNull String value) {
- if (mHostExtras == null) {
- mHostExtras = new Bundle();
+ @RequiresApi(21)
+ public void setHostExtras(@NonNull PersistableBundle extras) {
+ mHostExtras = ConvertPersistableBundleApi21Impl.toBundle(extras);
+ }
+
+ @RequiresApi(21)
+ private static class ConvertPersistableBundleApi21Impl {
+ private ConvertPersistableBundleApi21Impl() {}
+ static Bundle toBundle(@NonNull PersistableBundle extras) {
+ return new Bundle(extras);
}
- mHostExtras.putString(key, value);
}
diff --git a/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java b/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java
index 4e52c6b..d770648 100644
--- a/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java
+++ b/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java
@@ -31,7 +31,9 @@
import android.content.Intent;
import android.net.Uri;
import android.net.wifi.WifiManager;
+import android.os.Build;
import android.os.Handler;
+import android.os.PersistableBundle;
import android.provider.Settings;
import android.text.SpannableString;
import android.text.TextUtils;
@@ -1397,11 +1399,7 @@
}
private Slice createTtsSlice(Uri sliceUri) {
- Slice slice = new ListBuilder(getContext(), sliceUri, INFINITY)
- // Attach additional information for host. Depending on the host apps, this
- // information might or might not be used.
- // In this case, SliceBrowser is customized to play TTS when binding the slice.
- .setHostExtra("tts", "hello world")
+ ListBuilder slice = new ListBuilder(getContext(), sliceUri, INFINITY)
.addRow(
new RowBuilder().setPrimaryAction(
SliceAction.create(
@@ -1410,8 +1408,25 @@
R.drawable.message),
ICON_IMAGE, "TTS"
)
- ).setTitle("Text to speech").setSubtitle("Play")).build();
- return slice;
+ ).setTitle("Text to speech").setSubtitle("Play"));
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ SetHostExtraApi21Impl.setHostExtra(slice, "tts", "hello world");
+ }
+
+ return slice.build();
+ }
+
+ @RequiresApi(21)
+ private static class SetHostExtraApi21Impl {
+ private SetHostExtraApi21Impl() {}
+ static void setHostExtra(ListBuilder listBuilder, String key, String value) {
+ PersistableBundle extras = new PersistableBundle();
+ extras.putString("tts", "hello world");
+ // Attach additional information for host. Depending on the host apps, this
+ // information might or might not be used.
+ // In this case, SliceBrowser is customized to play TTS when binding the slice.
+ listBuilder.setHostExtras(extras);
+ }
}
private PendingIntent getIntent(String action) {
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowStyle.java b/slices/view/src/main/java/androidx/slice/widget/RowStyle.java
index 05055df..a8dffd3 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowStyle.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowStyle.java
@@ -95,7 +95,9 @@
mDisableRecyclerViewItemAnimator = a.getBoolean(
R.styleable.RowStyle_disableRecyclerViewItemAnimator, false);
mImageSize = (int) a.getDimension(
- R.styleable.RowStyle_imageSize, UNBOUNDED);
+ R.styleable.RowStyle_imageSize,
+ context.getResources().getDimensionPixelSize(
+ R.dimen.abc_slice_small_image_size));
} finally {
a.recycle();
}
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowView.java b/slices/view/src/main/java/androidx/slice/widget/RowView.java
index 4a6eed8..9531f93 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowView.java
@@ -178,7 +178,6 @@
private int mImageSize;
private int mIconSize;
- private int mStyleRowHeight = HEIGHT_UNBOUND;
// How big mRangeBar wants to be.
private int mMeasuredRangeHeight;
@@ -921,7 +920,6 @@
container.addView(iv);
}
if (mSliceStyle != null) {
- mStyleRowHeight = mSliceStyle.getRowMinHeight();
if (mSliceStyle.getRowStyle() != null) {
int styleIconSize = mSliceStyle.getRowStyle().getIconSize();
mIconSize = styleIconSize > 0 ? styleIconSize : mIconSize;
@@ -936,8 +934,8 @@
iv.setLayoutParams(lp);
int p = 0;
if (isIcon) {
- p = mStyleRowHeight == HEIGHT_UNBOUND
- ? mIconSize / 2 : (mStyleRowHeight - mIconSize) / 2;
+ p = mImageSize == HEIGHT_UNBOUND
+ ? mIconSize / 2 : (mImageSize - mIconSize) / 2;
}
iv.setPadding(p, p, p, p);
addedView = iv;
diff --git a/slices/view/src/main/java/androidx/slice/widget/SliceActionView.java b/slices/view/src/main/java/androidx/slice/widget/SliceActionView.java
index b2700f5..b3c6b97 100644
--- a/slices/view/src/main/java/androidx/slice/widget/SliceActionView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/SliceActionView.java
@@ -78,7 +78,6 @@
private int mIconSize;
private int mImageSize;
- private int mStyleRowHeight = HEIGHT_UNBOUND;
public SliceActionView(Context context, SliceStyle style) {
super(context);
@@ -86,7 +85,6 @@
mIconSize = res.getDimensionPixelSize(R.dimen.abc_slice_icon_size);
mImageSize = res.getDimensionPixelSize(R.dimen.abc_slice_small_image_size);
if (style != null) {
- mStyleRowHeight = style.getRowMinHeight();
if (style.getRowStyle() != null) {
mIconSize = style.getRowStyle().getIconSize();
mImageSize = style.getRowStyle().getImageSize();
@@ -176,8 +174,8 @@
mActionView.setLayoutParams(lp);
int p = 0;
if (action.getImageMode() == ICON_IMAGE) {
- p = mStyleRowHeight == HEIGHT_UNBOUND
- ? mIconSize / 2 : (mStyleRowHeight - mIconSize) / 2;
+ p = mImageSize == HEIGHT_UNBOUND
+ ? mIconSize / 2 : (mImageSize - mIconSize) / 2;
}
mActionView.setPadding(p, p, p, p);
int touchFeedbackAttr = android.R.attr.selectableItemBackground;
diff --git a/slices/view/src/main/res/values-bs/strings.xml b/slices/view/src/main/res/values-bs/strings.xml
index cb84c18..2a42cd4 100644
--- a/slices/view/src/main/res/values-bs/strings.xml
+++ b/slices/view/src/main/res/values-bs/strings.xml
@@ -22,9 +22,9 @@
<string name="abc_slice_show_more" msgid="1567717014004692768">"Prikaži više"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Ažurirano <xliff:g id="TIME">%1$s</xliff:g>"</string>
<plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one">Prije <xliff:g id="ID_2">%d</xliff:g> min.</item>
- <item quantity="few">Prije <xliff:g id="ID_2">%d</xliff:g> min.</item>
- <item quantity="other">Prije <xliff:g id="ID_2">%d</xliff:g> min.</item>
+ <item quantity="one">Prije <xliff:g id="ID_2">%d</xliff:g> min</item>
+ <item quantity="few">Prije <xliff:g id="ID_2">%d</xliff:g> min</item>
+ <item quantity="other">Prije <xliff:g id="ID_2">%d</xliff:g> min</item>
</plurals>
<plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
<item quantity="one">Prije <xliff:g id="ID_2">%d</xliff:g> god.</item>
diff --git a/slices/view/src/main/res/values-hy/strings.xml b/slices/view/src/main/res/values-hy/strings.xml
index fcf96af..962f469 100644
--- a/slices/view/src/main/res/values-hy/strings.xml
+++ b/slices/view/src/main/res/values-hy/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="abc_slice_more" msgid="1983560225998630901">"Ավելին"</string>
- <string name="abc_slice_show_more" msgid="1567717014004692768">"Ցուցադրել ավելի շատ"</string>
+ <string name="abc_slice_show_more" msgid="1567717014004692768">"Ցույց տալ ավելի շատ"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Թարմացվել է <xliff:g id="TIME">%1$s</xliff:g>"</string>
<plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
<item quantity="one"><xliff:g id="ID_2">%d</xliff:g> րոպե առաջ</item>
diff --git a/textclassifier/textclassifier/src/main/res/values-cs/strings.xml b/textclassifier/textclassifier/src/main/res/values-cs/strings.xml
index 2d1c5d2..5a999f5 100644
--- a/textclassifier/textclassifier/src/main/res/values-cs/strings.xml
+++ b/textclassifier/textclassifier/src/main/res/values-cs/strings.xml
@@ -26,7 +26,7 @@
<string name="sms_desc" msgid="7733202356868441148">"Napsat SMS na vybrané telefonní číslo"</string>
<string name="add_contact" msgid="386263007484061034">"Přidat"</string>
<string name="add_contact_desc" msgid="1739272501140197425">"Přidat do kontaktů"</string>
- <string name="floating_toolbar_open_overflow_description" msgid="6778458701858708647">"Více možností"</string>
+ <string name="floating_toolbar_open_overflow_description" msgid="6778458701858708647">"Další možnosti"</string>
<string name="floating_toolbar_close_overflow_description" msgid="3112942430227166657">"Zavřít rozbalovací nabídku"</string>
<string name="abc_share" msgid="37557693057519685">"Sdílet"</string>
</resources>
diff --git a/tv-provider/tv-provider/api/current.txt b/tv-provider/tv-provider/api/current.txt
index 663790c..1c3721b 100644
--- a/tv-provider/tv-provider/api/current.txt
+++ b/tv-provider/tv-provider/api/current.txt
@@ -467,6 +467,7 @@
field public static final int ASPECT_RATIO_MOVIE_POSTER = 5; // 0x5
field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
field public static final int AVAILABILITY_FREE = 4; // 0x4
+ field public static final int AVAILABILITY_FREE_WITH_ADS = 5; // 0x5
field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
@@ -669,6 +670,7 @@
field public static final int ASPECT_RATIO_MOVIE_POSTER = 5; // 0x5
field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
field public static final int AVAILABILITY_FREE = 4; // 0x4
+ field public static final int AVAILABILITY_FREE_WITH_ADS = 5; // 0x5
field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
diff --git a/tv-provider/tv-provider/api/public_plus_experimental_current.txt b/tv-provider/tv-provider/api/public_plus_experimental_current.txt
index 663790c..1c3721b 100644
--- a/tv-provider/tv-provider/api/public_plus_experimental_current.txt
+++ b/tv-provider/tv-provider/api/public_plus_experimental_current.txt
@@ -467,6 +467,7 @@
field public static final int ASPECT_RATIO_MOVIE_POSTER = 5; // 0x5
field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
field public static final int AVAILABILITY_FREE = 4; // 0x4
+ field public static final int AVAILABILITY_FREE_WITH_ADS = 5; // 0x5
field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
@@ -669,6 +670,7 @@
field public static final int ASPECT_RATIO_MOVIE_POSTER = 5; // 0x5
field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
field public static final int AVAILABILITY_FREE = 4; // 0x4
+ field public static final int AVAILABILITY_FREE_WITH_ADS = 5; // 0x5
field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
diff --git a/tv-provider/tv-provider/api/restricted_current.txt b/tv-provider/tv-provider/api/restricted_current.txt
index 2e09571..7c04939 100644
--- a/tv-provider/tv-provider/api/restricted_current.txt
+++ b/tv-provider/tv-provider/api/restricted_current.txt
@@ -526,6 +526,7 @@
field public static final int ASPECT_RATIO_MOVIE_POSTER = 5; // 0x5
field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
field public static final int AVAILABILITY_FREE = 4; // 0x4
+ field public static final int AVAILABILITY_FREE_WITH_ADS = 5; // 0x5
field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
diff --git a/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/BasePreviewProgram.java b/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/BasePreviewProgram.java
index 97f5f71..99fc0d9 100644
--- a/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/BasePreviewProgram.java
+++ b/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/BasePreviewProgram.java
@@ -107,7 +107,8 @@
PreviewProgramColumns.AVAILABILITY_FREE_WITH_SUBSCRIPTION,
PreviewProgramColumns.AVAILABILITY_PAID_CONTENT,
PreviewProgramColumns.AVAILABILITY_PURCHASED,
- PreviewProgramColumns.AVAILABILITY_FREE
+ PreviewProgramColumns.AVAILABILITY_FREE,
+ PreviewProgramColumns.AVAILABILITY_FREE_WITH_ADS,
})
@Retention(RetentionPolicy.SOURCE)
@RestrictTo(LIBRARY)
@@ -830,9 +831,11 @@
* {@link androidx.tvprovider.media.tv.TvContractCompat
* .PreviewPrograms#AVAILABILITY_PAID_CONTENT},
* {@link androidx.tvprovider.media.tv.TvContractCompat
- * .PreviewPrograms#AVAILABILITY_PURCHASED}, and
+ * .PreviewPrograms#AVAILABILITY_PURCHASED},
* {@link androidx.tvprovider.media.tv.TvContractCompat
- * .PreviewPrograms#AVAILABILITY_FREE}.
+ * .PreviewPrograms#AVAILABILITY_FREE}, and
+ * {@link androidx.tvprovider.media.tv.TvContractCompat
+ * .PreviewPrograms#AVAILABILITY_FREE_WITH_ADS}.
*
* @param availability The availability of the program.
* @return This Builder object to allow for chaining of calls to builder methods.
diff --git a/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java b/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
index 05de3ea..dfd6c3a 100644
--- a/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
+++ b/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
@@ -1123,6 +1123,13 @@
int AVAILABILITY_FREE = 4;
/**
+ * The availability for free with ads content.
+ *
+ * @see #COLUMN_AVAILABILITY
+ */
+ int AVAILABILITY_FREE_WITH_ADS = 5;
+
+ /**
* The interaction type for "views".
*
* @see #COLUMN_INTERACTION_TYPE
diff --git a/ui/settings.gradle b/ui/settings.gradle
index 42928da..b08fe43 100644
--- a/ui/settings.gradle
+++ b/ui/settings.gradle
@@ -52,9 +52,9 @@
includeProject(":compose:animation:animation-core:samples", "../compose/animation/animation-core/samples")
includeProject(":compose:animation:animation:integration-tests:animation-demos", "../compose/animation/animation/integration-tests/animation-demos")
includeProject(":compose:animation:animation:samples", "../compose/animation/animation/samples")
-includeProject(":compose:compose-compiler", "../compose/compose-compiler")
-includeProject(":compose:compose-compiler-hosted", "../compose/compose-compiler-hosted")
-includeProject(":compose:compose-compiler-hosted:integration-tests", "../compose/compose-compiler-hosted/integration-tests")
+includeProject(":compose:compiler:compiler", "../compose/compiler/compiler")
+includeProject(":compose:compiler:compiler-hosted", "../compose/compiler/compiler-hosted")
+includeProject(":compose:compiler:compiler-hosted:integration-tests", "../compose/compiler/compiler-hosted/integration-tests")
if (!startParameter.projectProperties.containsKey('compose.desktop.disable')) {
includeProject(":compose:desktop", "../compose/desktop")
includeProject(":compose:desktop:desktop", "../compose/desktop/desktop")
diff --git a/ui/ui-animation-tooling-internal/src/main/java/androidx/compose/animation/tooling/ComposeAnimation.kt b/ui/ui-animation-tooling-internal/src/main/java/androidx/compose/animation/tooling/ComposeAnimation.kt
index aa14ffb..15fb737 100644
--- a/ui/ui-animation-tooling-internal/src/main/java/androidx/compose/animation/tooling/ComposeAnimation.kt
+++ b/ui/ui-animation-tooling-internal/src/main/java/androidx/compose/animation/tooling/ComposeAnimation.kt
@@ -51,9 +51,9 @@
val states: Set<Any>
@Suppress("DocumentExceptions")
get() =
- throw UnsupportedOperationException(
- "Only available when getType() is TRANSITION_ANIMATION"
- )
+ throw UnsupportedOperationException(
+ "Only available when getType() is TRANSITION_ANIMATION"
+ )
/**
* A label which can be used to represent the animation as text in Android Studio.
diff --git a/ui/ui-test/build.gradle b/ui/ui-test/build.gradle
index ad41d3b..373bcb3c 100644
--- a/ui/ui-test/build.gradle
+++ b/ui/ui-test/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
}
kotlin {
diff --git a/ui/ui-test/src/androidMain/kotlin/androidx/ui/test/AndroidAssertions.kt b/ui/ui-test/src/androidMain/kotlin/androidx/ui/test/AndroidAssertions.kt
index b28b5e3..6ef9bb4 100644
--- a/ui/ui-test/src/androidMain/kotlin/androidx/ui/test/AndroidAssertions.kt
+++ b/ui/ui-test/src/androidMain/kotlin/androidx/ui/test/AndroidAssertions.kt
@@ -62,7 +62,7 @@
composeView.getLocationInWindow(it)
Offset(it[0].toFloat(), it[1].toFloat())
}
- return boundsInRoot.shift(rootLocationInWindow)
+ return boundsInRoot.translate(rootLocationInWindow)
}
@OptIn(ExperimentalLayoutNodeApi::class)
diff --git a/ui/ui-test/src/commonMain/kotlin/androidx/ui/test/Actions.kt b/ui/ui-test/src/commonMain/kotlin/androidx/ui/test/Actions.kt
index 4117b30..aeee257 100644
--- a/ui/ui-test/src/commonMain/kotlin/androidx/ui/test/Actions.kt
+++ b/ui/ui-test/src/commonMain/kotlin/androidx/ui/test/Actions.kt
@@ -71,7 +71,7 @@
val parentInRoot = scrollableNode.componentNode.coordinates.parentCoordinates
?.positionInRoot ?: Offset.Zero
- val viewPort = viewPortInParent.shift(parentInRoot)
+ val viewPort = viewPortInParent.translate(parentInRoot)
val target = Rect(node.positionInRoot, node.size.toSize())
val mustScrollUp = target.bottom > viewPort.bottom
diff --git a/ui/ui-tooling/build.gradle b/ui/ui-tooling/build.gradle
index 8d21b69..e094d2a 100644
--- a/ui/ui-tooling/build.gradle
+++ b/ui/ui-tooling/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- kotlinPlugin project(path: ":compose:compose-compiler")
+ kotlinPlugin project(path: ":compose:compiler:compiler")
implementation(KOTLIN_STDLIB)
diff --git a/ui/ui-tooling/src/main/java/androidx/ui/tooling/preview/Preview.kt b/ui/ui-tooling/src/main/java/androidx/ui/tooling/preview/Preview.kt
index daac164..3c465d1 100644
--- a/ui/ui-tooling/src/main/java/androidx/ui/tooling/preview/Preview.kt
+++ b/ui/ui-tooling/src/main/java/androidx/ui/tooling/preview/Preview.kt
@@ -38,7 +38,7 @@
* @param heightDp Max height in DP the annotated @[Composable] will be rendered in. Use this to
* restrict the size of the rendering viewport.
* @param locale Current user preference for the locale, corresponding to
- * [locale]({@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier) resource
+ * [locale](https://d.android.com/guide/topics/resources/providing-resources.html#LocaleQualifier) resource
* qualifier. By default, the `default` folder will be used.
* @param fontScale User preference for the scaling factor for fonts, relative to the base
* density scaling.
@@ -46,7 +46,7 @@
* The @[Composable] will be render in the context of a full activity.
* @param showBackground If true, the @[Composable] will use a default background color.
* @param backgroundColor The 32-bit ARGB color int for the background or 0 if not set
- * @param uiMode Bit mask of the ui mode as per [android.content.res.Configuration#uiMode]
+ * @param uiMode Bit mask of the ui mode as per [android.content.res.Configuration.uiMode]
* @param device Device string indicating the device to use in the preview. See the available
* devices in [Devices].
*/
diff --git a/wear/wear-watchface-data/build.gradle b/wear/wear-watchface-data/build.gradle
index e3f539a..f2cb67a 100644
--- a/wear/wear-watchface-data/build.gradle
+++ b/wear/wear-watchface-data/build.gradle
@@ -29,10 +29,12 @@
dependencies {
api("androidx.annotation:annotation:1.1.0")
+ api("androidx.versionedparcelable:versionedparcelable:1.1.0")
api(project(":wear:wear-complications-data"))
api(KOTLIN_STDLIB)
implementation("androidx.core:core:1.1.0")
+ annotationProcessor(project(":versionedparcelable:versionedparcelable-compiler"))
}
android {
diff --git a/wear/wear-watchface-data/src/main/aidl/android/support/wearable/watchface/IWatchFaceCommand.aidl b/wear/wear-watchface-data/src/main/aidl/android/support/wearable/watchface/IWatchFaceCommand.aidl
index 2e0f8a0..2c65ffa 100644
--- a/wear/wear-watchface-data/src/main/aidl/android/support/wearable/watchface/IWatchFaceCommand.aidl
+++ b/wear/wear-watchface-data/src/main/aidl/android/support/wearable/watchface/IWatchFaceCommand.aidl
@@ -17,6 +17,9 @@
package android.support.wearable.watchface;
import android.support.wearable.complications.ComplicationData;
+import androidx.wear.watchface.data.ImmutableSystemState;
+import androidx.wear.watchface.data.IndicatorState;
+import androidx.wear.watchface.data.SystemState;
/**
* Interface for controlling the watchface from the wearable device.
@@ -48,30 +51,18 @@
/**
* Sends the current system state to the Watch Face.
*/
- void setSystemState(
- in boolean inAmbientMode,
- in int interruptionFilter,
- in int unreadCount,
- in int notificationCount
- ) = 3;
+ void setSystemState(in SystemState systemState) = 3;
/**
- * Sends the current system state to the Watch Face, only called if
+ * Sends the current watch indicator state to the Watch Face, only called if
* {@link WatchFaceStyle#hideNotificationIndicator} is true.
*/
- void setIndicatorState(
- in boolean isCharging,
- in boolean inAirplaneMode,
- in boolean isConnectedToCompanion,
- in boolean inTheaterMode,
- in boolean isGpsActive,
- in boolean isKeyguardLocked
- ) = 4;
+ void setIndicatorState(in IndicatorState indicatorState) = 4;
/**
* Sends the immutable system state to the Watch Face.
*/
- void setImmutableSystemState(in boolean hasLowBitAmbient, in boolean hasBurnInProtection) = 5;
+ void setImmutableSystemState(in ImmutableSystemState immutableSystemState) = 5;
/**
* Sends new complication data for the specified complicationId.
@@ -101,12 +92,15 @@
* @param drawMode The {@link androidx.wear.watchface.DrawMode} to render with
* @param compressionQuality The WebP compression quality, 100 = lossless
* @param calendarTimeMillis The calendar time (millis since the epoch) to render with
+ * @param style A {@link Bundle} containing a mapping from {@link UserStyleCategory} to
+ * {@link UserStyleCategory.Option}s. If null then the current style is used.
* @return A bundle containing a compressed shared memory backed {@link Bitmap} of the watch
* face with the requested settings
*/
Bundle takeWatchfaceScreenshot(in int drawMode,
in int compressionQuality,
- in long calendarTimeMillis) = 9;
+ in long calendarTimeMillis,
+ in Bundle style) = 9;
/**
* Request for a {@link Bundle} containing a WebP compressed shared memory backed {@link Bitmap}
@@ -120,6 +114,8 @@
* @param calendarTimeMillis The calendar time (millis since the epoch) to render with
* @param complicationData The {@link ComplicationData} to render the complication with, if
* null then the last ComplicationData sent to the watch face if any is used
+ * @param style A {@link Bundle} containing a mapping from {@link UserStyleCategory} to
+ * {@link UserStyleCategory.Option}s. If null then the current style is used.
* @return A bundle containing a compressed shared memory backed {@link Bitmap} of the
* complication with the requested settings
*/
@@ -127,7 +123,8 @@
in int drawMode,
in int compressionQuality,
in long calendarTimeMillis,
- in ComplicationData complicationData) = 10;
+ in ComplicationData complicationData,
+ in Bundle style) = 10;
/**
* Forwards a touch event for the WatchFace to process.
diff --git a/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/ImmutableSystemState.aidl b/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/ImmutableSystemState.aidl
new file mode 100644
index 0000000..c5ada43
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/ImmutableSystemState.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2020 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 androidx.wear.watchface.data;
+
+/** @hide */
+parcelable ImmutableSystemState;
diff --git a/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/IndicatorState.aidl b/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/IndicatorState.aidl
new file mode 100644
index 0000000..f61ccdf
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/IndicatorState.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2020 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 androidx.wear.watchface.data;
+
+/** @hide */
+parcelable IndicatorState;
diff --git a/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/SystemState.aidl b/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/SystemState.aidl
new file mode 100644
index 0000000..e648e52
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/SystemState.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2020 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 androidx.wear.watchface.data;
+
+/** @hide */
+parcelable SystemState;
diff --git a/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/ImmutableSystemState.java b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/ImmutableSystemState.java
new file mode 100644
index 0000000..442c0f0
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/ImmutableSystemState.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2020 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 androidx.wear.watchface.data;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.versionedparcelable.ParcelField;
+import androidx.versionedparcelable.ParcelUtils;
+import androidx.versionedparcelable.VersionedParcelable;
+import androidx.versionedparcelable.VersionedParcelize;
+
+/**
+ * Data sent over AIDL for {@link IWatchFaceCommand#setSystemState}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@VersionedParcelize
+public final class ImmutableSystemState implements VersionedParcelable {
+ @ParcelField(1)
+ boolean mHasLowBitAmbient;
+
+ @ParcelField(2)
+ boolean mHasBurnInProtection;
+
+ /** Used by VersionedParcelable. */
+ ImmutableSystemState() {}
+
+ public ImmutableSystemState(
+ boolean hasLowBitAmbient,
+ boolean hasBurnInProtection) {
+ mHasLowBitAmbient = hasLowBitAmbient;
+ mHasBurnInProtection = hasBurnInProtection;
+ }
+
+ public boolean getHasLowBitAmbient() {
+ return mHasLowBitAmbient;
+ }
+
+ public boolean getHasBurnInProtection() {
+ return mHasBurnInProtection;
+ }
+
+ /** Serializes this SystemState to the specified {@link Parcel}. */
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeParcelable(ParcelUtils.toParcelable(this), flags);
+ }
+
+ public static final Parcelable.Creator<ImmutableSystemState> CREATOR =
+ new Parcelable.Creator<ImmutableSystemState>() {
+ @Override
+ public ImmutableSystemState createFromParcel(Parcel source) {
+ return ImmutableSystemStateParcelizer.read(
+ ParcelUtils.fromParcelable(source.readParcelable(
+ getClass().getClassLoader())));
+ }
+
+ @Override
+ public ImmutableSystemState[] newArray(int size) {
+ return new ImmutableSystemState[size];
+ }
+ };
+}
diff --git a/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/IndicatorState.java b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/IndicatorState.java
new file mode 100644
index 0000000..adc9bb1
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/IndicatorState.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2020 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 androidx.wear.watchface.data;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.versionedparcelable.ParcelField;
+import androidx.versionedparcelable.ParcelUtils;
+import androidx.versionedparcelable.VersionedParcelable;
+import androidx.versionedparcelable.VersionedParcelize;
+
+/**
+ * Data sent over AIDL for {@link IWatchFaceCommand#setIndicatorState}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@VersionedParcelize
+public final class IndicatorState implements VersionedParcelable {
+ @ParcelField(1)
+ boolean mIsCharging;
+
+ @ParcelField(2)
+ boolean mInAirplaneMode;
+
+ @ParcelField(3)
+ boolean mIsConnectedToCompanion;
+
+ @ParcelField(4)
+ boolean mInTheaterMode;
+
+ @ParcelField(5)
+ boolean mIsGpsActive;
+
+ @ParcelField(6)
+ boolean mIsKeyguardLocked;
+
+ /** Used by VersionedParcelable. */
+ IndicatorState() {}
+
+ public IndicatorState(
+ boolean isCharging,
+ boolean inAirplaneMode,
+ boolean isConnectedToCompanion,
+ boolean inTheaterMode,
+ boolean isGpsActive,
+ boolean isKeyguardLocked) {
+ mIsCharging = isCharging;
+ mInAirplaneMode = inAirplaneMode;
+ mIsConnectedToCompanion = isConnectedToCompanion;
+ mInTheaterMode = inTheaterMode;
+ mIsGpsActive = isGpsActive;
+ mIsKeyguardLocked = isKeyguardLocked;
+ }
+
+ public boolean getIsCharging() {
+ return mIsCharging;
+ }
+
+ public boolean getInAirplaneMode() {
+ return mInAirplaneMode;
+ }
+
+ public boolean getIsConnectedToCompanion() {
+ return mIsConnectedToCompanion;
+ }
+
+ public boolean getInTheaterMode() {
+ return mInTheaterMode;
+ }
+
+ public boolean getIsGpsActive() {
+ return mIsGpsActive;
+ }
+
+ public boolean getIsKeyguardLocked() {
+ return mIsKeyguardLocked;
+ }
+
+ /** Serializes this SystemState to the specified {@link Parcel}. */
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeParcelable(ParcelUtils.toParcelable(this), flags);
+ }
+
+ public static final Parcelable.Creator<IndicatorState> CREATOR =
+ new Parcelable.Creator<IndicatorState>() {
+ @Override
+ public IndicatorState createFromParcel(Parcel source) {
+ return IndicatorStateParcelizer.read(
+ ParcelUtils.fromParcelable(source.readParcelable(
+ getClass().getClassLoader())));
+ }
+
+ @Override
+ public IndicatorState[] newArray(int size) {
+ return new IndicatorState[size];
+ }
+ };
+}
diff --git a/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/SystemState.java b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/SystemState.java
new file mode 100644
index 0000000..943d17f2
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/SystemState.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2020 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 androidx.wear.watchface.data;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.versionedparcelable.ParcelField;
+import androidx.versionedparcelable.ParcelUtils;
+import androidx.versionedparcelable.VersionedParcelable;
+import androidx.versionedparcelable.VersionedParcelize;
+
+/**
+ * Data sent over AIDL for {@link IWatchFaceCommand#setSystemState}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@VersionedParcelize
+public final class SystemState implements VersionedParcelable {
+ @ParcelField(1)
+ boolean mInAmbientMode;
+
+ @ParcelField(2)
+ int mInterruptionFilter;
+
+ @ParcelField(3)
+ int mUnreadCount;
+
+ @ParcelField(4)
+ int mNotificationCount;
+
+ /** Used by VersionedParcelable. */
+ SystemState() {}
+
+ public SystemState(
+ boolean inAmbientMode,
+ int interruptionFilter,
+ int unreadCount,
+ int notificationCount) {
+ mInAmbientMode = inAmbientMode;
+ mInterruptionFilter = interruptionFilter;
+ mUnreadCount = unreadCount;
+ mNotificationCount = notificationCount;
+ }
+
+ public boolean getInAmbientMode() {
+ return mInAmbientMode;
+ }
+
+ public int getInterruptionFilter() {
+ return mInterruptionFilter;
+ }
+
+ public int getUnreadCount() {
+ return mUnreadCount;
+ }
+
+ public int getNotificationCount() {
+ return mNotificationCount;
+ }
+
+ /** Serializes this SystemState to the specified {@link Parcel}. */
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeParcelable(ParcelUtils.toParcelable(this), flags);
+ }
+
+ public static final Parcelable.Creator<SystemState> CREATOR =
+ new Parcelable.Creator<SystemState>() {
+ @Override
+ public SystemState createFromParcel(Parcel source) {
+ return SystemStateParcelizer.read(
+ ParcelUtils.fromParcelable(source.readParcelable(
+ getClass().getClassLoader())));
+ }
+
+ @Override
+ public SystemState[] newArray(int size) {
+ return new SystemState[size];
+ }
+ };
+}
diff --git a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/BooleanUserStyleCategory.kt b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/BooleanUserStyleCategory.kt
index e10303f..a4af9a2 100644
--- a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/BooleanUserStyleCategory.kt
+++ b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/BooleanUserStyleCategory.kt
@@ -42,14 +42,43 @@
icon: Icon?,
/** The default value for this BooleanUserStyleCategory. */
- defaultValue: Boolean
- ) : super(
+ defaultValue: Boolean,
+
+ /**
+ * Used by the style configuration UI. Describes which rendering layer this style affects.
+ * Must be either 0 (for a style change with no visual effect, e.g. sound controls) or a
+ * combination of {@link #LAYER_WATCH_FACE_BASE}, {@link #LAYER_COMPLICATONS}, {@link
+ * #LAYER_UPPER}.
+ */
+ layerFlags: Int
+ ) : this(
id,
displayName,
description,
icon,
listOf(BooleanOption(true), BooleanOption(false)),
- BooleanOption(defaultValue)
+ defaultValue,
+ layerFlags
+ )
+
+ // Helper lets us obey the contract that the default value's object must be in the options list.
+ private constructor(
+ id: String,
+ displayName: String,
+ description: String,
+ icon: Icon?,
+ options: List<BooleanOption>,
+ defaultValue: Boolean,
+ layerFlags: Int
+ ) : super(
+ id,
+ displayName,
+ description,
+ icon,
+ options,
+ options.first
+ { it.value == defaultValue },
+ layerFlags
)
internal constructor(bundle: Bundle) : super(bundle)
diff --git a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/DoubleRangeUserStyleCategory.kt b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/DoubleRangeUserStyleCategory.kt
index dd92123..701c858 100644
--- a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/DoubleRangeUserStyleCategory.kt
+++ b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/DoubleRangeUserStyleCategory.kt
@@ -28,6 +28,26 @@
internal companion object {
internal const val CATEGORY_TYPE = "DoubleRangeUserStyleCategory"
internal const val OPTION_TYPE = "DoubleRangeOption"
+
+ internal fun createOptionsList(
+ minimumValue: Double,
+ maximumValue: Double,
+ defaultValue: Double
+ ): List<DoubleRangeOption> {
+ require(minimumValue < maximumValue)
+ require(defaultValue >= minimumValue)
+ require(defaultValue <= maximumValue)
+
+ return if (defaultValue != minimumValue && defaultValue != maximumValue) {
+ listOf(
+ DoubleRangeOption(minimumValue),
+ DoubleRangeOption(defaultValue),
+ DoubleRangeOption(maximumValue)
+ )
+ } else {
+ listOf(DoubleRangeOption(minimumValue), DoubleRangeOption(maximumValue))
+ }
+ }
}
constructor (
@@ -50,14 +70,42 @@
maximumValue: Double,
/** The default value for this DoubleRangeUserStyleCategory. */
- defaultValue: Double
+ defaultValue: Double,
+
+ /**
+ * Used by the style configuration UI. Describes which rendering layer this style affects.
+ * Must be either 0 (for a style change with no visual effect, e.g. sound controls) or a
+ * combination of {@link #LAYER_WATCH_FACE_BASE}, {@link #LAYER_COMPLICATONS}, {@link
+ * #LAYER_UPPER}.
+ */
+ layerFlags: Int
+ ) : this(
+ id,
+ displayName,
+ description,
+ icon,
+ createOptionsList(minimumValue, maximumValue, defaultValue),
+ defaultValue,
+ layerFlags
+ )
+
+ // Helper lets us obey the contract that the default value's object must be in the options list.
+ private constructor(
+ id: String,
+ displayName: String,
+ description: String,
+ icon: Icon?,
+ options: List<DoubleRangeOption>,
+ defaultValue: Double,
+ layerFlags: Int
) : super(
id,
displayName,
description,
icon,
- listOf(DoubleRangeOption(minimumValue), DoubleRangeOption(maximumValue)),
- DoubleRangeOption(defaultValue)
+ options,
+ options.first { it.value == defaultValue },
+ layerFlags
)
internal constructor(bundle: Bundle) : super(bundle)
diff --git a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/ListUserStyleCategory.kt b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/ListUserStyleCategory.kt
index 99c61fc..7adb030 100644
--- a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/ListUserStyleCategory.kt
+++ b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/ListUserStyleCategory.kt
@@ -45,9 +45,17 @@
/** List of all options for this ListUserStyleCategory. */
options: List<ListOption>,
+ /**
+ * Used by the style configuration UI. Describes which rendering layer this style affects.
+ * Must be either 0 (for a style change with no visual effect, e.g. sound controls) or a
+ * combination of {@link #LAYER_WATCH_FACE_BASE}, {@link #LAYER_COMPLICATONS}, {@link
+ * #LAYER_UPPER}.
+ */
+ layerFlags: Int,
+
/** The default option, used when data isn't persisted. */
defaultOption: ListOption = options.first()
- ) : super(id, displayName, description, icon, options, defaultOption)
+ ) : super(id, displayName, description, icon, options, defaultOption, layerFlags)
internal constructor(bundle: Bundle) : super(bundle)
diff --git a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/LongRangeUserStyleCategory.kt b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/LongRangeUserStyleCategory.kt
index 936b445..bb4a70e 100644
--- a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/LongRangeUserStyleCategory.kt
+++ b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/LongRangeUserStyleCategory.kt
@@ -28,6 +28,29 @@
internal companion object {
internal const val CATEGORY_TYPE = "LongRangeUserStyleCategory"
internal const val OPTION_TYPE = "LongRangeOption"
+
+ internal fun createOptionsList(
+ minimumValue: Long,
+ maximumValue: Long,
+ defaultValue: Long
+ ): List<LongRangeOption> {
+ require(minimumValue < maximumValue)
+ require(defaultValue >= minimumValue)
+ require(defaultValue <= maximumValue)
+
+ return if (defaultValue != minimumValue && defaultValue != maximumValue) {
+ listOf(
+ LongRangeOption(minimumValue),
+ LongRangeOption(defaultValue),
+ LongRangeOption(maximumValue)
+ )
+ } else {
+ listOf(
+ LongRangeOption(minimumValue),
+ LongRangeOption(maximumValue)
+ )
+ }
+ }
}
constructor (
@@ -50,14 +73,42 @@
maximumValue: Long,
/** The default value for this LongRangeUserStyleCategory. */
- defaultValue: Long
+ defaultValue: Long,
+
+ /**
+ * Used by the style configuration UI. Describes which rendering layer this style affects.
+ * Must be either 0 (for a style change with no visual effect, e.g. sound controls) or a
+ * combination of {@link #LAYER_WATCH_FACE_BASE}, {@link #LAYER_COMPLICATONS}, {@link
+ * #LAYER_UPPER}.
+ */
+ layerFlags: Int
+ ) : this(
+ id,
+ displayName,
+ description,
+ icon,
+ createOptionsList(minimumValue, maximumValue, defaultValue),
+ defaultValue,
+ layerFlags
+ )
+
+ // Helper lets us obey the contract that the default value's object must be in the options list.
+ private constructor(
+ id: String,
+ displayName: String,
+ description: String,
+ icon: Icon?,
+ options: List<LongRangeOption>,
+ defaultValue: Long,
+ layerFlags: Int
) : super(
id,
displayName,
description,
icon,
- listOf(LongRangeOption(minimumValue), LongRangeOption(maximumValue)),
- LongRangeOption(defaultValue)
+ options,
+ options.first { it.value == defaultValue },
+ layerFlags
)
internal constructor(bundle: Bundle) : super(bundle)
diff --git a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleCategory.kt b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleCategory.kt
index 4cdd4e5..c46fdd3 100644
--- a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleCategory.kt
+++ b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleCategory.kt
@@ -46,16 +46,40 @@
val options: List<Option>,
/** The default option if nothing has been selected. Must be in the {@link #options} list.*/
- val defaultOption: Option
+ val defaultOption: Option,
+
+ /**
+ * Used by the style configuration UI. Describes which rendering layer this style affects. Must
+ * be either 0 (for a style change with no visual effect, e.g. sound controls) or a combination
+ * of {@link #LAYER_WATCH_FACE_BASE}, {@link #LAYER_COMPLICATONS},
+ * {@link #LAYER_WATCH_FACE_UPPER}.
+ */
+ val layerFlags: Int
) {
companion object {
+ /**
+ * The base watch face without complications or watch hands (or any other elements that
+ * could occlude complications).
+ */
+ const val LAYER_WATCH_FACE_BASE = 1 shl 0
+
+ /** The complications layer. */
+ const val LAYER_COMPLICATONS = 1 shl 1
+
+ /** Anything that could occlude complications, typically watch hands. */
+ const val LAYER_WATCH_FACE_UPPER = 1 shl 2
+
+ internal const val INVALID_LAYER_MASK =
+ (LAYER_WATCH_FACE_BASE or LAYER_COMPLICATONS or LAYER_WATCH_FACE_UPPER).inv()
+
internal const val KEY_CATEGORY_TYPE = "KEY_CATEGORY_TYPE"
- internal const val KEY_DEFAULT_OPTION = "KEY_DEFAULT_OPTION"
+ internal const val KEY_DEFAULT_OPTION_INDEX = "KEY_DEFAULT_OPTION_INDEX"
internal const val KEY_DESCRIPTION = "KEY_DESCRIPTION"
internal const val KEY_DISPLAY_NAME = "KEY_DISPLAY_NAME"
internal const val KEY_ICON = "KEY_ICON"
internal const val KEY_OPTIONS = "KEY_OPTIONS"
internal const val KEY_STYLE_CATEGORY_ID = "KEY_STYLE_CATEGORY_ID"
+ internal const val KEY_LAYER_FLAGS = "KEY_LAYER_FLAGS"
/**
* Constructs an {@link UserStyleCategory} serialized in a {@link Bundle}.
@@ -78,6 +102,16 @@
}
}
+ init {
+ require(layerFlags and INVALID_LAYER_MASK == 0) {
+ "layerFlags must be either 0 or a combination of LAYER_WATCH_FACE_BASE, " +
+ "LAYER_COMPLICATONS, LAYER_WATCH_FACE_UPPER"
+ }
+ require(options.contains(defaultOption)) {
+ "The defaultOption must be in the options list"
+ }
+ }
+
internal fun getCategoryOptionForId(id: String?) =
if (id == null) {
defaultOption
@@ -86,12 +120,18 @@
}
internal constructor(bundle: Bundle) : this(
+ bundle,
+ StyleUtils.readOptionsListFromBundle(bundle)
+ )
+
+ private constructor(bundle: Bundle, options: List<Option>) : this(
bundle.getString(KEY_STYLE_CATEGORY_ID)!!,
bundle.getString(KEY_DISPLAY_NAME)!!,
bundle.getString(KEY_DESCRIPTION)!!,
bundle.getParcelable(KEY_ICON),
- StyleUtils.readOptionsListFromBundle(bundle),
- Option.createFromBundle(bundle.getBundle(KEY_DEFAULT_OPTION)!!)
+ options,
+ options[bundle.getInt(KEY_DEFAULT_OPTION_INDEX)],
+ bundle.getInt(KEY_LAYER_FLAGS)
)
@CallSuper
@@ -101,10 +141,8 @@
bundle.putString(KEY_DISPLAY_NAME, displayName)
bundle.putString(KEY_DESCRIPTION, description)
bundle.putParcelable(KEY_ICON, icon)
- bundle.putBundle(
- KEY_DEFAULT_OPTION,
- Bundle().apply { defaultOption.writeToBundle(this) }
- )
+ bundle.putInt(KEY_DEFAULT_OPTION_INDEX, options.indexOf(defaultOption))
+ bundle.putInt(KEY_LAYER_FLAGS, layerFlags)
StyleUtils.writeOptionListToBundle(options, bundle)
}
diff --git a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/StyleUtilsTest.kt b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/StyleUtilsTest.kt
index 3d72660..62d6150 100644
--- a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/StyleUtilsTest.kt
+++ b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/StyleUtilsTest.kt
@@ -38,7 +38,12 @@
fun bundleAndUnbundleStyleCategoryAndOption() {
val categoryIcon = Icon.createWithContentUri("categoryIcon")
val styleCategory = ListUserStyleCategory(
- "id", "displayName", "description", categoryIcon, listOf(option1, option2, option3)
+ "id",
+ "displayName",
+ "description",
+ categoryIcon,
+ listOf(option1, option2, option3),
+ UserStyleCategory.LAYER_WATCH_FACE_BASE
)
val bundle = Bundle()
@@ -51,6 +56,7 @@
assertThat(unbundled.displayName).isEqualTo("displayName")
assertThat(unbundled.description).isEqualTo("description")
assertThat(unbundled.icon!!.uri.toString()).isEqualTo("categoryIcon")
+ assertThat(unbundled.layerFlags).isEqualTo(UserStyleCategory.LAYER_WATCH_FACE_BASE)
val optionArray =
unbundled.options.filterIsInstance<ListUserStyleCategory.ListOption>()
.toTypedArray()
@@ -92,10 +98,20 @@
val categoryIcon1 = Icon.createWithContentUri("categoryIcon1")
val categoryIcon2 = Icon.createWithContentUri("categoryIcon2")
val styleCategory1 = ListUserStyleCategory(
- "id1", "displayName1", "description1", categoryIcon1, listOf(option1, option2)
+ "id1",
+ "displayName1",
+ "description1",
+ categoryIcon1,
+ listOf(option1, option2),
+ UserStyleCategory.LAYER_WATCH_FACE_BASE
)
val styleCategory2 = ListUserStyleCategory(
- "id2", "displayName2", "description2", categoryIcon2, listOf(option3, option4)
+ "id2",
+ "displayName2",
+ "description2",
+ categoryIcon2,
+ listOf(option3, option4),
+ UserStyleCategory.LAYER_WATCH_FACE_UPPER
)
val bundles = StyleUtils.userStyleCategoriesToBundles(
@@ -109,6 +125,7 @@
assertThat(unbundled[0].displayName).isEqualTo("displayName1")
assertThat(unbundled[0].description).isEqualTo("description1")
assertThat(unbundled[0].icon!!.uri.toString()).isEqualTo("categoryIcon1")
+ assertThat(unbundled[0].layerFlags).isEqualTo(UserStyleCategory.LAYER_WATCH_FACE_BASE)
val optionArray1 =
unbundled[0].options.filterIsInstance<ListUserStyleCategory.ListOption>()
.toTypedArray()
@@ -125,6 +142,7 @@
assertThat(unbundled[1].displayName).isEqualTo("displayName2")
assertThat(unbundled[1].description).isEqualTo("description2")
assertThat(unbundled[1].icon!!.uri.toString()).isEqualTo("categoryIcon2")
+ assertThat(unbundled[1].layerFlags).isEqualTo(UserStyleCategory.LAYER_WATCH_FACE_UPPER)
val optionArray2 =
unbundled[1].options.filterIsInstance<ListUserStyleCategory.ListOption>()
.toTypedArray()
@@ -142,10 +160,20 @@
val categoryIcon1 = Icon.createWithContentUri("categoryIcon1")
val categoryIcon2 = Icon.createWithContentUri("categoryIcon2")
val styleCategory1 = ListUserStyleCategory(
- "id1", "displayName1", "description1", categoryIcon1, listOf(option1, option2)
+ "id1",
+ "displayName1",
+ "description1",
+ categoryIcon1,
+ listOf(option1, option2),
+ UserStyleCategory.LAYER_WATCH_FACE_BASE
)
val styleCategory2 = ListUserStyleCategory(
- "id2", "displayName2", "description2", categoryIcon2, listOf(option3, option4)
+ "id2",
+ "displayName2",
+ "description2",
+ categoryIcon2,
+ listOf(option3, option4),
+ UserStyleCategory.LAYER_WATCH_FACE_UPPER
)
val schema = listOf(styleCategory1, styleCategory2)
val styleMap = mapOf(
diff --git a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleCategoryTest.kt b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleCategoryTest.kt
index 8fd836d..e83cf0a 100644
--- a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleCategoryTest.kt
+++ b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleCategoryTest.kt
@@ -16,31 +16,13 @@
package androidx.wear.watchface.style
-import android.graphics.drawable.Icon
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.model.FrameworkMethod
-import org.robolectric.RobolectricTestRunner
-import org.robolectric.internal.bytecode.InstrumentationConfiguration
-// Without this we get test failures with an error:
-// "failed to access class kotlin.jvm.internal.DefaultConstructorMarker".
-class WatchFaceServiceTestRunner(testClass: Class<*>) : RobolectricTestRunner(testClass) {
- override fun createClassLoaderConfig(method: FrameworkMethod): InstrumentationConfiguration =
- InstrumentationConfiguration.Builder(super.createClassLoaderConfig(method))
- .doNotInstrumentPackage("androidx.wear.watchface.style")
- .build()
-}
-
-@RunWith(WatchFaceServiceTestRunner::class)
+@RunWith(StyleTestRunner::class)
class UserStyleCategoryTest {
- private val icon1 = Icon.createWithContentUri("icon1")
- private val icon2 = Icon.createWithContentUri("icon2")
- private val icon3 = Icon.createWithContentUri("icon3")
- private val icon4 = Icon.createWithContentUri("icon4")
-
@Test
fun rangedUserStyleCategory_getOptionForId_returns_default_for_bad_input() {
val defaultValue = 0.75
@@ -52,7 +34,8 @@
null,
0.0,
1.0,
- defaultValue
+ defaultValue,
+ UserStyleCategory.LAYER_WATCH_FACE_BASE
)
assertThat(rangedUserStyleCategory.getOptionForId("not a number").id)
@@ -76,7 +59,8 @@
null,
0.0,
1.0,
- defaultValue
+ defaultValue,
+ UserStyleCategory.LAYER_WATCH_FACE_BASE
)
assertThat(rangedUserStyleCategory.getOptionForId("0").id)
diff --git a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleRepositoryTest.kt b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleRepositoryTest.kt
index c26f164..805a899 100644
--- a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleRepositoryTest.kt
+++ b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleRepositoryTest.kt
@@ -39,7 +39,8 @@
"Colors",
"Watchface colorization", /* icon = */
null,
- colorStyleList
+ colorStyleList,
+ UserStyleCategory.LAYER_WATCH_FACE_BASE
)
private val classicStyleOption =
@@ -59,7 +60,8 @@
"Hand Style",
"Hand visual look", /* icon = */
null,
- watchHandStyleList
+ watchHandStyleList,
+ UserStyleCategory.LAYER_WATCH_FACE_UPPER
)
private val mockListener1 = Mockito.mock(UserStyleRepository.UserStyleListener::class.java)
diff --git a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasWatchFaceService.kt b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasWatchFaceService.kt
index dd1a307..83d887b 100644
--- a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasWatchFaceService.kt
+++ b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasWatchFaceService.kt
@@ -87,7 +87,10 @@
"Green",
Icon.createWithResource(this, R.drawable.green_style)
)
- )
+ ),
+ UserStyleCategory.LAYER_WATCH_FACE_BASE or
+ UserStyleCategory.LAYER_COMPLICATONS or
+ UserStyleCategory.LAYER_WATCH_FACE_UPPER
)
val drawHourPipsStyleCategory =
BooleanUserStyleCategory(
@@ -95,7 +98,8 @@
"Hour Pips",
"Whether to draw or not",
null,
- true
+ true,
+ UserStyleCategory.LAYER_WATCH_FACE_BASE
)
val watchHandLengthStyleCategory =
DoubleRangeUserStyleCategory(
@@ -105,7 +109,8 @@
null,
0.25,
1.0,
- 0.75
+ 0.75,
+ UserStyleCategory.LAYER_WATCH_FACE_UPPER
)
val userStyleRepository = UserStyleRepository(
listOf(colorStyleCategory, drawHourPipsStyleCategory, watchHandLengthStyleCategory)
diff --git a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt
index bf54ed4..0fb9449 100644
--- a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt
+++ b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt
@@ -34,6 +34,7 @@
import androidx.wear.watchface.WatchFaceType
import androidx.wear.watchface.WatchState
import androidx.wear.watchface.style.ListUserStyleCategory
+import androidx.wear.watchface.style.UserStyleCategory
import androidx.wear.watchface.style.UserStyleRepository
import java.nio.ByteBuffer
import java.nio.ByteOrder
@@ -83,7 +84,8 @@
"Green",
Icon.createWithResource(this, R.drawable.green_style)
)
- )
+ ),
+ UserStyleCategory.LAYER_WATCH_FACE_BASE or UserStyleCategory.LAYER_WATCH_FACE_UPPER
)
val userStyleRepository = UserStyleRepository(listOf(colorStyleCategory))
val complicationSlots = ComplicationsManager(emptyList())
diff --git a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt
index 14a8b28..0010dd3 100644
--- a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt
+++ b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt
@@ -73,7 +73,10 @@
"Blue",
icon = null
)
- )
+ ),
+ UserStyleCategory.LAYER_WATCH_FACE_BASE or
+ UserStyleCategory.LAYER_COMPLICATONS or
+ UserStyleCategory.LAYER_WATCH_FACE_UPPER
),
ListUserStyleCategory(
"hand_style_category",
@@ -92,7 +95,8 @@
"Gothic",
icon = null
)
- )
+ ),
+ UserStyleCategory.LAYER_WATCH_FACE_UPPER
)
)
)
diff --git a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestCanvasWatchFaceService.kt b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestCanvasWatchFaceService.kt
index f66a499..8f33b99 100644
--- a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestCanvasWatchFaceService.kt
+++ b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestCanvasWatchFaceService.kt
@@ -25,6 +25,7 @@
import androidx.wear.complications.SystemProviders
import androidx.wear.watchface.Complication
import androidx.wear.watchface.ComplicationsManager
+import androidx.wear.watchface.MutableWatchState
import androidx.wear.watchface.NoInvalidateWatchFaceHostApi
import androidx.wear.watchface.WatchFace
import androidx.wear.watchface.WatchFaceHost
@@ -39,6 +40,7 @@
import androidx.wear.watchface.style.BooleanUserStyleCategory
import androidx.wear.watchface.style.DoubleRangeUserStyleCategory
import androidx.wear.watchface.style.ListUserStyleCategory
+import androidx.wear.watchface.style.UserStyleCategory
import androidx.wear.watchface.style.UserStyleRepository
/** A simple canvas test watch face for integration tests. */
@@ -48,6 +50,10 @@
var mockSystemTimeMillis: Long
) : WatchFaceService() {
+ private val mutableWatchState = MutableWatchState().apply {
+ isAmbient.value = false
+ }
+
init {
attachBaseContext(testContext)
}
@@ -58,7 +64,7 @@
watchState: WatchState
): WatchFace {
// Override is necessary because the watch face isn't visible in this test.
- watchState.onVisibilityChanged(true)
+ mutableWatchState.isVisible.value = true
val watchFaceStyle = WatchFaceColorStyle.create(this, "red_style")
val colorStyleCategory = ListUserStyleCategory(
@@ -77,7 +83,10 @@
"Green",
Icon.createWithResource(this, R.drawable.green_style)
)
- )
+ ),
+ UserStyleCategory.LAYER_WATCH_FACE_BASE or
+ UserStyleCategory.LAYER_COMPLICATONS or
+ UserStyleCategory.LAYER_WATCH_FACE_UPPER
)
val drawHourPipsStyleCategory =
BooleanUserStyleCategory(
@@ -85,7 +94,8 @@
"Hour Pips",
"Whether or not hour pips should be drawn",
null,
- true
+ true,
+ UserStyleCategory.LAYER_WATCH_FACE_BASE
)
val watchHandLengthStyleCategory =
DoubleRangeUserStyleCategory(
@@ -95,7 +105,8 @@
null,
0.25,
1.0,
- 1.0
+ 1.0,
+ UserStyleCategory.LAYER_WATCH_FACE_UPPER
)
val userStyleRepository = UserStyleRepository(
listOf(colorStyleCategory, drawHourPipsStyleCategory, watchHandLengthStyleCategory)
@@ -160,5 +171,7 @@
}).build()
}
+ override fun getMutableWatchState() = mutableWatchState
+
override fun getHandler() = handler
}
diff --git a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestGlesWatchFaceService.kt b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestGlesWatchFaceService.kt
index cf7a17e..5df4dda 100644
--- a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestGlesWatchFaceService.kt
+++ b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestGlesWatchFaceService.kt
@@ -21,6 +21,7 @@
import android.os.Handler
import android.view.SurfaceHolder
import androidx.wear.watchface.ComplicationsManager
+import androidx.wear.watchface.MutableWatchState
import androidx.wear.watchface.NoInvalidateWatchFaceHostApi
import androidx.wear.watchface.WatchFace
import androidx.wear.watchface.WatchFaceHost
@@ -30,6 +31,7 @@
import androidx.wear.watchface.samples.ExampleOpenGLRenderer
import androidx.wear.watchface.samples.R
import androidx.wear.watchface.style.ListUserStyleCategory
+import androidx.wear.watchface.style.UserStyleCategory
import androidx.wear.watchface.style.UserStyleRepository
/** A simple OpenGL test watch face for integration tests. */
@@ -39,6 +41,10 @@
var mockSystemTimeMillis: Long
) : WatchFaceService() {
+ private val mutableWatchState = MutableWatchState().apply {
+ isAmbient.value = false
+ }
+
init {
attachBaseContext(testContext)
}
@@ -49,7 +55,7 @@
watchState: WatchState
): WatchFace {
// Override is necessary because the watch face isn't visible in this test.
- watchState.onVisibilityChanged(true)
+ mutableWatchState.isVisible.value = true
val colorStyleCategory = ListUserStyleCategory(
"color_style_category",
@@ -67,7 +73,8 @@
"Green",
Icon.createWithResource(this, R.drawable.green_style)
)
- )
+ ),
+ UserStyleCategory.LAYER_WATCH_FACE_BASE or UserStyleCategory.LAYER_WATCH_FACE_UPPER
)
val userStyleRepository = UserStyleRepository(listOf(colorStyleCategory))
val complicationSlots = ComplicationsManager(emptyList())
@@ -94,5 +101,7 @@
}).build()
}
+ override fun getMutableWatchState() = mutableWatchState
+
override fun getHandler() = handler
}
diff --git a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt
index 5278b1d..d36ef74 100644
--- a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt
+++ b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt
@@ -44,6 +44,7 @@
import androidx.wear.watchface.ComplicationBoundsType
import androidx.wear.watchface.DrawMode
import androidx.wear.watchface.WatchFaceService
+import androidx.wear.watchface.data.SystemState
import androidx.wear.watchface.samples.EXAMPLE_CANVAS_WATCHFACE_LEFT_COMPLICATION_ID
import org.junit.Before
import org.junit.Rule
@@ -247,10 +248,12 @@
private fun setAmbient(ambient: Boolean) {
watchFaceServiceStub.iWatchFaceCommand!!.setSystemState(
- ambient,
- 0,
- 0,
- 0
+ SystemState(
+ ambient,
+ 0,
+ 0,
+ 0
+ )
)
}
@@ -287,10 +290,9 @@
bitmap = watchFaceServiceStub.iWatchFaceCommand!!.takeWatchfaceScreenshot(
DrawMode.AMBIENT,
100,
- 123456789
- ).ashmemCompressedImageBundleToBitmap(
-
- )
+ 123456789,
+ null
+ ).ashmemCompressedImageBundleToBitmap()
latch.countDown()
}
@@ -313,10 +315,9 @@
DrawMode.AMBIENT,
100,
123456789,
+ null,
null
- ).ashmemCompressedImageBundleToBitmap(
-
- )
+ ).ashmemCompressedImageBundleToBitmap()
latch.countDown()
}
@@ -337,7 +338,8 @@
bitmap = watchFaceServiceStub.iWatchFaceCommand!!.takeWatchfaceScreenshot(
DrawMode.INTERACTIVE,
100,
- 123456789
+ 123456789,
+ null
).ashmemCompressedImageBundleToBitmap()!!
latch.countDown()
}
@@ -364,10 +366,9 @@
ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
.setShortTitle(ComplicationText.plainText("Title"))
.setShortText(ComplicationText.plainText("Text"))
- .build()
- ).ashmemCompressedImageBundleToBitmap(
-
- )
+ .build(),
+ null
+ ).ashmemCompressedImageBundleToBitmap()
latch.countDown()
}
@@ -388,6 +389,7 @@
DrawMode.INTERACTIVE,
100,
123456789,
+ null,
null
).ashmemCompressedImageBundleToBitmap()
latch2.countDown()
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/CanvasRenderer.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/CanvasRenderer.kt
index 912361f..71cc90b 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/CanvasRenderer.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/CanvasRenderer.kt
@@ -73,7 +73,7 @@
surfaceHolder.lockCanvas()
}) ?: return
try {
- if (watchState.isVisible) {
+ if (watchState.isVisible.value) {
render(canvas, surfaceHolder.surfaceFrame, calendar)
} else {
canvas.drawColor(Color.BLACK)
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Complication.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Complication.kt
index afda9b6..78bac5c 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Complication.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Complication.kt
@@ -25,6 +25,7 @@
import android.icu.util.Calendar
import android.support.wearable.complications.ComplicationData
import androidx.annotation.UiThread
+import androidx.lifecycle.Observer
import androidx.wear.complications.SystemProviders
import androidx.wear.complications.rendering.ComplicationDrawable
@@ -116,36 +117,41 @@
get() = _drawable
set(value) {
_drawable = value
- _drawable.inAmbientMode = watchState.isAmbient
- _drawable.lowBitAmbient = watchState.hasLowBitAmbient
- _drawable.setBurnInProtection(watchState.hasBurnInProtection)
+ _drawable.inAmbientMode = watchState.isAmbient.value
+ _drawable.lowBitAmbient = watchState.hasLowBitAmbient.value
+ _drawable.setBurnInProtection(watchState.hasBurnInProtection.value)
attachedComplication?.scheduleUpdateActiveComplications()
}
- private inner class SystemStateListener : WatchState.Listener {
- override fun onAmbientModeChanged(isAmbient: Boolean) {
- drawable.inAmbientMode = isAmbient
- }
+ private val isAmbientObserver = Observer<Boolean> {
+ drawable.inAmbientMode = it
}
- private val systemStateListener = SystemStateListener()
+ private val lowBitAmbientObserver = Observer<Boolean> {
+ drawable.lowBitAmbient = it
+ }
+
+ private val burnInProtectionObserver = Observer<Boolean> {
+ drawable.setBurnInProtection(it)
+ }
+
private var attachedComplication: Complication? = null
private var complicationData: ComplicationData? = null
/** {@inheritDoc} */
override fun onAttach(complication: Complication) {
attachedComplication = complication
- drawable.inAmbientMode = watchState.isAmbient
- drawable.lowBitAmbient = watchState.hasLowBitAmbient
- drawable.setBurnInProtection(watchState.hasBurnInProtection)
-
- watchState.addListener(systemStateListener)
+ watchState.isAmbient.observe(isAmbientObserver)
+ watchState.hasLowBitAmbient.observe(lowBitAmbientObserver)
+ watchState.hasBurnInProtection.observe(burnInProtectionObserver)
}
/** {@inheritDoc} */
override fun onDetach() {
- watchState.removeListener(systemStateListener)
+ watchState.isAmbient.removeObserver(isAmbientObserver)
+ watchState.hasLowBitAmbient.removeObserver(lowBitAmbientObserver)
+ watchState.hasBurnInProtection.removeObserver(burnInProtectionObserver)
attachedComplication = null
}
@@ -198,7 +204,7 @@
class Complication internal constructor(
internal val id: Int,
@ComplicationBoundsType internal val boundsType: Int,
- val unitSquareBounds: RectF,
+ unitSquareBounds: RectF,
renderer: ComplicationRenderer,
internal val supportedTypes: IntArray,
internal val defaultProviderPolicy: DefaultComplicationProviderPolicy,
@@ -305,12 +311,27 @@
private lateinit var complicationsManager: ComplicationsManager
private lateinit var invalidateCallback: ComplicationRenderer.InvalidateCallback
- private var _enabled = true
+ private var _unitSquareBounds = unitSquareBounds
+ var unitSquareBounds: RectF
+ @UiThread
+ get() = _unitSquareBounds
+
+ @UiThread
+ set(value) {
+ _unitSquareBounds = value
+
+ // The caller might modify a number of complications. For efficiency we need to coalesce
+ // these into one update task.
+ complicationsManager.scheduleUpdateActiveComplications()
+ }
+
+ private var _enabled = true
var enabled: Boolean
@JvmName("isEnabled")
@UiThread
get() = _enabled
+
@UiThread
set(value) {
_enabled = value
@@ -321,10 +342,10 @@
}
private var _renderer = renderer
-
var renderer: ComplicationRenderer
@UiThread
get() = _renderer
+
@UiThread
set(value) {
renderer.onDetach()
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
index f8f66db..eae10ae 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
@@ -147,5 +147,5 @@
* @return Whether we should schedule an onDraw call to maintain an interactive frame rate
*/
@UiThread
- open fun shouldAnimate() = watchState.isVisible && !watchState.isAmbient
+ open fun shouldAnimate() = watchState.isVisible.value && !watchState.isAmbient.value
}
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchData.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchData.kt
new file mode 100644
index 0000000..ad5255b
--- /dev/null
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchData.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2020 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 androidx.wear.watchface
+
+import androidx.annotation.UiThread
+import androidx.lifecycle.Observer
+
+/**
+ * An observable UI thread only data holder class.
+ *
+ * @param <T> The type of data hold by this instance
+ */
+open class WatchData<T> protected constructor(protected var _value: T?) {
+ private var iterating = false
+ internal val observers = ArrayList<Observer<T>>()
+ internal val toBeRemoved = HashSet<Observer<T>>()
+
+ /** Whether or not this WatchData contains a value. */
+ fun hasValue() = _value != null
+
+ /** Returns the value contained within this WatchData or default if there isn't one. */
+ fun getValueOr(default: T) = if (_value != null) {
+ _value!!
+ } else {
+ default
+ }
+
+ open var value: T
+ @UiThread
+ get() = _value!!
+
+ @UiThread
+ protected set(v) {
+ require(!iterating)
+ iterating = true
+ _value = v
+ for (observer in observers) {
+ // The observer might unregister itself and removing elements from a collection
+ // while it's being iterated is not allowed, so check if we should skip over this
+ // observer.
+ if (!toBeRemoved.contains(observer)) {
+ observer.onChanged(_value)
+ }
+ }
+ iterating = false
+ for (observer in toBeRemoved) {
+ observers.remove(observer)
+ }
+ }
+
+ /**
+ * Adds the given observer to the observers list. The events are dispatched on the ui thread.
+ * If there's any data held within the WatchData it will be immediately delivered to the
+ * observer.
+ */
+ @UiThread
+ fun observe(observer: Observer<T>) {
+ require(!observers.contains(observer))
+ observers.add(observer)
+ if (hasValue()) {
+ observer.onChanged(_value)
+ }
+ }
+
+ /** Removes an observer previously added by {@link observe}. */
+ @UiThread
+ fun removeObserver(observer: Observer<T>) {
+ require(observers.contains(observer))
+
+ if (iterating) {
+ toBeRemoved.add(observer)
+ } else {
+ observers.remove(observer)
+ }
+ }
+}
+
+/**
+ * {@link WatchData} which publicly exposes {@link #setValue(T)} method
+ *
+ * @param <T> The type of data hold by this instance
+ */
+@SuppressWarnings("WeakerAccess")
+class MutableWatchData<T>(initialValue: T?) : WatchData<T>(initialValue) {
+ constructor() : this(null)
+
+ override var value: T
+ @UiThread
+ get() = _value!!
+
+ @UiThread
+ public set(v) {
+ super.value = v
+ }
+}
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
index 16b9e29..49e2704 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
@@ -39,10 +39,11 @@
import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
import androidx.annotation.UiThread
import androidx.annotation.VisibleForTesting
+import androidx.lifecycle.Observer
import androidx.wear.complications.SystemProviders
-import androidx.wear.watchface.style.StyleUtils
import androidx.wear.watchface.style.UserStyleCategory
import androidx.wear.watchface.style.UserStyleRepository
+import androidx.wear.watchface.style.StyleUtils
import androidx.wear.watchface.ui.WatchFaceConfigActivity
import androidx.wear.watchface.ui.WatchFaceConfigDelegate
import java.io.FileNotFoundException
@@ -370,14 +371,12 @@
val batteryLevelReceiver: BroadcastReceiver = object : BroadcastReceiver() {
@SuppressWarnings("SyntheticAccessor")
override fun onReceive(context: Context, intent: Intent) {
+ val isBatteryLowAndNotCharging =
+ watchState.isBatteryLowAndNotCharging as MutableWatchData
when (intent.action) {
- Intent.ACTION_BATTERY_LOW -> watchState.onIsBatteryLowAndNotCharging(true)
- Intent.ACTION_BATTERY_OKAY -> watchState.onIsBatteryLowAndNotCharging(
- false
- )
- Intent.ACTION_POWER_CONNECTED -> watchState.onIsBatteryLowAndNotCharging(
- false
- )
+ Intent.ACTION_BATTERY_LOW -> isBatteryLowAndNotCharging.value = true
+ Intent.ACTION_BATTERY_OKAY -> isBatteryLowAndNotCharging.value = false
+ Intent.ACTION_POWER_CONNECTED -> isBatteryLowAndNotCharging.value = false
}
invalidate()
}
@@ -462,38 +461,31 @@
watchFaceHostApi.setCurrentUserStyle(userStyle)
}
- private inner class SystemStateListener : WatchState.Listener {
- @SuppressWarnings("SyntheticAccessor")
- override fun onAmbientModeChanged(isAmbient: Boolean) {
- scheduleDraw()
+ private val ambientObserver = Observer<Boolean> {
+ scheduleDraw()
+ invalidate()
+ }
+
+ private val interruptionFilterObserver = Observer<Int> {
+ val inMuteMode = it == NotificationManager.INTERRUPTION_FILTER_NONE
+ if (muteMode != inMuteMode) {
+ muteMode = inMuteMode
invalidate()
}
-
- @SuppressWarnings("SyntheticAccessor")
- override fun onInterruptionFilterChanged(interruptionFilter: Int) {
- val inMuteMode = interruptionFilter == NotificationManager.INTERRUPTION_FILTER_NONE
- if (muteMode != inMuteMode) {
- muteMode = inMuteMode
- invalidate()
- }
- }
-
- @SuppressWarnings("SyntheticAccessor")
- override fun onVisibilityChanged(visible: Boolean) {
- if (visible) {
- registerReceivers()
- // Update time zone in case it changed while we weren't visible.
- calendar.timeZone = TimeZone.getDefault()
- invalidate()
- } else {
- unregisterReceivers()
- }
-
- scheduleDraw()
- }
}
- private val systemStateListener = SystemStateListener()
+ private val visibilityObserver = Observer<Boolean> {
+ if (it) {
+ registerReceivers()
+ // Update time zone in case it changed while we weren't visible.
+ calendar.timeZone = TimeZone.getDefault()
+ invalidate()
+ } else {
+ unregisterReceivers()
+ }
+
+ scheduleDraw()
+ }
init {
// We need to inhibit an immediate callback during initialization because members are not
@@ -572,8 +564,9 @@
watchFaceHostApi.registerWatchFaceType(watchFaceType)
watchFaceHostApi.registerUserStyleSchema(userStyleRepository.userStyleCategories)
-
- watchState.addListener(systemStateListener)
+ watchState.isAmbient.observe(ambientObserver)
+ watchState.interruptionFilter.observe(interruptionFilterObserver)
+ watchState.isVisible.observe(visibilityObserver)
userStyleRepository.addUserStyleListener(styleListener)
sendCurrentUserStyle(userStyleRepository.userStyle)
@@ -595,7 +588,9 @@
pendingUpdateTime.cancel()
pendingPostDoubleTap.cancel()
renderer.onDestroy()
- watchState.removeListener(systemStateListener)
+ watchState.isAmbient.removeObserver(ambientObserver)
+ watchState.interruptionFilter.removeObserver(interruptionFilterObserver)
+ watchState.isVisible.removeObserver(visibilityObserver)
userStyleRepository.removeUserStyleListener(styleListener)
WatchFaceConfigActivity.unregisterWatchFace(componentName)
}
@@ -635,6 +630,12 @@
}
private fun scheduleDraw() {
+ // Separate calls are issued to deliver the state of isAmbient and isVisible, so during init
+ // we might not yet know the state of both (which is required by the shouldAnimate logic).
+ if (!watchState.isAmbient.hasValue() || !watchState.isVisible.hasValue()) {
+ return
+ }
+
setCalendarTime(systemTimeProvider.getSystemTimeMillis())
if (renderer.shouldAnimate()) {
pendingUpdateTime.postUnique {
@@ -676,14 +677,14 @@
/** @hide */
@UiThread
internal fun maybeUpdateDrawMode() {
- var newDrawMode = if (watchState.isBatteryLowAndNotCharging) {
+ var newDrawMode = if (watchState.isBatteryLowAndNotCharging.getValueOr(false)) {
DrawMode.LOW_BATTERY_INTERACTIVE
} else {
DrawMode.INTERACTIVE
}
// Watch faces may wish to run an animation while entering ambient mode and we let them
// defer entering ambient mode.
- if (watchState.isAmbient && !renderer.shouldAnimate()) {
+ if (watchState.isAmbient.value && !renderer.shouldAnimate()) {
newDrawMode = DrawMode.AMBIENT
} else if (muteMode) {
newDrawMode = DrawMode.MUTE
@@ -719,7 +720,7 @@
Long {
// Limit update rate to conserve power when the battery is low and not charging.
val updateRateMillis =
- if (watchState.isBatteryLowAndNotCharging) {
+ if (watchState.isBatteryLowAndNotCharging.getValueOr(false)) {
max(interactiveUpdateRateMillis, MAX_LOW_POWER_INTERACTIVE_UPDATE_RATE_MS)
} else {
interactiveUpdateRateMillis
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
index 51e087a..b15eeff 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
@@ -37,13 +37,16 @@
import android.support.wearable.watchface.Constants
import android.support.wearable.watchface.IWatchFaceCommand
import android.support.wearable.watchface.IWatchFaceService
-import android.support.wearable.watchface.toAshmemCompressedImageBundle
import android.support.wearable.watchface.accessibility.ContentDescriptionLabel
+import android.support.wearable.watchface.toAshmemCompressedImageBundle
import android.util.Log
import android.view.Choreographer
import android.view.SurfaceHolder
import androidx.annotation.IntDef
import androidx.wear.complications.SystemProviders.ProviderId
+import androidx.wear.watchface.data.ImmutableSystemState
+import androidx.wear.watchface.data.IndicatorState
+import androidx.wear.watchface.data.SystemState
import androidx.wear.watchface.style.StyleUtils
import androidx.wear.watchface.style.UserStyleCategory
import java.util.concurrent.CountDownLatch
@@ -257,7 +260,7 @@
internal open fun getHandler() = Handler(Looper.getMainLooper())
// This is open to allow mocking.
- internal open fun getSystemState() = WatchState()
+ internal open fun getMutableWatchState() = MutableWatchState()
internal inner class EngineWrapper(
private val _handler: Handler
@@ -272,8 +275,8 @@
internal lateinit var iWatchFaceService: IWatchFaceService
internal lateinit var watchFace: WatchFace
- internal val systemState = getSystemState().apply {
- onVisibilityChanged(isVisible)
+ internal val mutableWatchState = getMutableWatchState().apply {
+ isVisible.value = this@EngineWrapper.isVisible
}
private var timeTickRegistered = false
@@ -335,14 +338,14 @@
var returnVal: R? = null
var exception: Exception? = null
if (_handler.post {
- try {
- returnVal = task.invoke()
- } catch (e: Exception) {
- // Will rethrow on the calling thread.
- exception = e
- }
- latch.countDown()
- }) {
+ try {
+ returnVal = task.invoke()
+ } catch (e: Exception) {
+ // Will rethrow on the calling thread.
+ exception = e
+ }
+ latch.countDown()
+ }) {
latch.await()
if (exception != null) {
throw exception as Exception
@@ -356,7 +359,7 @@
override fun ambientUpdate() {
runOnUiThread {
- if (systemState.isAmbient) {
+ if (mutableWatchState.isAmbient.value) {
ambientUpdateWakelock.acquire()
watchFace.invalidate()
ambientUpdateWakelock.acquire(SURFACE_DRAW_TIMEOUT_MS)
@@ -364,69 +367,75 @@
}
}
- override fun setSystemState(
- inAmbientMode: Boolean,
- interruptionFilter: Int,
- unreadCount: Int,
- notificationCount: Int
- ) {
+ override fun setSystemState(systemState: SystemState) {
runOnUiThread {
- if (firstSetSystemState || inAmbientMode != systemState.isAmbient) {
- systemState.onAmbientModeChanged(inAmbientMode)
+ if (firstSetSystemState ||
+ systemState.inAmbientMode != mutableWatchState.isAmbient.value
+ ) {
+ mutableWatchState.isAmbient.value = systemState.inAmbientMode
updateTimeTickReceiver()
}
- if (firstSetSystemState || interruptionFilter !=
- systemState.interruptionFilter
+ if (firstSetSystemState ||
+ systemState.interruptionFilter != mutableWatchState.interruptionFilter.value
) {
- systemState.onInterruptionFilterChanged(interruptionFilter)
+ mutableWatchState.interruptionFilter.value = systemState.interruptionFilter
}
- if (firstSetSystemState || unreadCount != systemState.unreadNotificationCount) {
- systemState.onUnreadNotificationCountChanged(unreadCount)
+ if (firstSetSystemState ||
+ systemState.unreadCount != mutableWatchState.unreadNotificationCount.value
+ ) {
+ mutableWatchState.unreadNotificationCount.value = systemState.unreadCount
}
- if (firstSetSystemState || notificationCount != systemState.notificationCount) {
- systemState.onNotificationCountChanged(notificationCount)
+ if (firstSetSystemState ||
+ systemState.notificationCount != mutableWatchState.notificationCount.value
+ ) {
+ mutableWatchState.notificationCount.value = systemState.notificationCount
}
firstSetSystemState = false
}
}
- override fun setIndicatorState(
- isCharging: Boolean,
- inAirplaneMode: Boolean,
- isConnectedToCompanion: Boolean,
- inTheaterMode: Boolean,
- isGpsActive: Boolean,
- isKeyguardLocked: Boolean
- ) {
+ override fun setIndicatorState(indicatorState: IndicatorState) {
runOnUiThread {
- if (firstIndicatorState || isCharging != systemState.isCharging) {
- systemState.onIsChargingChanged(isCharging)
- }
-
- if (firstIndicatorState || inAirplaneMode != systemState.inAirplaneMode) {
- systemState.onInAirplaneModeChanged(inAirplaneMode)
- }
-
- if (firstIndicatorState || isConnectedToCompanion !=
- systemState.isConnectedToCompanion
+ if (firstIndicatorState ||
+ indicatorState.isCharging != mutableWatchState.isCharging.value
) {
- systemState.onIsConnectedToCompanionChanged(isConnectedToCompanion)
+ mutableWatchState.isCharging.value = indicatorState.isCharging
}
- if (firstIndicatorState || inTheaterMode != systemState.isInTheaterMode) {
- systemState.onInTheaterModeChanged(inTheaterMode)
+ if (firstIndicatorState ||
+ indicatorState.inAirplaneMode != mutableWatchState.inAirplaneMode.value
+ ) {
+ mutableWatchState.inAirplaneMode.value = indicatorState.inAirplaneMode
}
- if (firstIndicatorState || isGpsActive != systemState.isGpsActive) {
- systemState.onIsGpsActiveChanged(isGpsActive)
+ if (firstIndicatorState ||
+ indicatorState.isConnectedToCompanion !=
+ mutableWatchState.isConnectedToCompanion.value
+ ) {
+ mutableWatchState.isConnectedToCompanion.value =
+ indicatorState.isConnectedToCompanion
}
- if (firstIndicatorState || isKeyguardLocked != systemState.isKeyguardLocked) {
- systemState.onIsKeyguardLockedChanged(isKeyguardLocked)
+ if (firstIndicatorState ||
+ indicatorState.inTheaterMode != mutableWatchState.isInTheaterMode.value
+ ) {
+ mutableWatchState.isInTheaterMode.value = indicatorState.inTheaterMode
+ }
+
+ if (firstIndicatorState ||
+ indicatorState.isGpsActive != mutableWatchState.isGpsActive.value
+ ) {
+ mutableWatchState.isGpsActive.value = indicatorState.isGpsActive
+ }
+
+ if (firstIndicatorState ||
+ indicatorState.isKeyguardLocked != mutableWatchState.isKeyguardLocked.value
+ ) {
+ mutableWatchState.isKeyguardLocked.value = indicatorState.isKeyguardLocked
}
firstIndicatorState = false
@@ -444,15 +453,14 @@
}
}
- override fun setImmutableSystemState(
- hasLowBitAmbient: Boolean,
- hasBurnInProtection: Boolean
- ) {
+ override fun setImmutableSystemState(immutableSystemState: ImmutableSystemState) {
runOnUiThread {
// These properties never change so set them once only.
if (!immutableSystemStateDone) {
- systemState.setHasLowBitAmbient(hasLowBitAmbient)
- systemState.setHasBurnInProtection(hasBurnInProtection)
+ mutableWatchState.hasLowBitAmbient.value =
+ immutableSystemState.hasLowBitAmbient
+ mutableWatchState.hasBurnInProtection.value =
+ immutableSystemState.hasBurnInProtection
immutableSystemStateDone = true
}
@@ -488,15 +496,33 @@
override fun takeWatchfaceScreenshot(
drawMode: Int,
compressionQuality: Int,
- calendarTimeMillis: Long
+ calendarTimeMillis: Long,
+ userStyle: Bundle?
): Bundle {
return runOnUiThread {
- watchFace.renderer.takeScreenshot(
+ val oldStyle = HashMap(watchFace.userStyleRepository.userStyle)
+ if (userStyle != null) {
+ watchFace.onSetStyleInternal(
+ StyleUtils.bundleToStyleMap(
+ userStyle,
+ watchFace.userStyleRepository.userStyleCategories
+ )
+ )
+ }
+
+ val bitmap = watchFace.renderer.takeScreenshot(
Calendar.getInstance().apply {
timeInMillis = calendarTimeMillis
},
drawMode
)
+
+ // Restore previous style if required.
+ if (userStyle != null) {
+ watchFace.onSetStyleInternal(oldStyle)
+ }
+
+ bitmap
}.toAshmemCompressedImageBundle(
compressionQuality
)
@@ -507,7 +533,8 @@
drawMode: Int,
compressionQuality: Int,
calendarTimeMillis: Long,
- complicationData: ComplicationData?
+ complicationData: ComplicationData?,
+ userStyle: Bundle?
): Bundle? {
return runOnUiThread {
val calendar = Calendar.getInstance().apply {
@@ -515,6 +542,16 @@
}
val complication = watchFace.complicationsManager[complicationId]
if (complication != null) {
+ val oldStyle = HashMap(watchFace.userStyleRepository.userStyle)
+ if (userStyle != null) {
+ watchFace.onSetStyleInternal(
+ StyleUtils.bundleToStyleMap(
+ userStyle,
+ watchFace.userStyleRepository.userStyleCategories
+ )
+ )
+ }
+
val bounds = complication.computeBounds(watchFace.renderer.screenBounds)
val complicationBitmap =
Bitmap.createBitmap(
@@ -535,11 +572,15 @@
drawMode
)
- // Restore previous ComplicationData if required.
+ // Restore previous ComplicationData & style if required.
if (complicationData != null) {
complication.renderer.setData(prevComplicationData)
}
+ if (userStyle != null) {
+ watchFace.onSetStyleInternal(oldStyle)
+ }
+
complicationBitmap.toAshmemCompressedImageBundle(
compressionQuality
)
@@ -644,21 +685,37 @@
}
watchFaceCommand.setSystemState(
- extras.getBoolean(Constants.EXTRA_AMBIENT_MODE, systemState.isAmbient),
- extras.getInt(Constants.EXTRA_INTERRUPTION_FILTER, systemState.interruptionFilter),
- extras.getInt(Constants.EXTRA_UNREAD_COUNT, systemState.unreadNotificationCount),
- extras.getInt(Constants.EXTRA_NOTIFICATION_COUNT, systemState.notificationCount)
+ SystemState(
+ extras.getBoolean(
+ Constants.EXTRA_AMBIENT_MODE,
+ mutableWatchState.isAmbient.getValueOr(false)
+ ),
+ extras.getInt(
+ Constants.EXTRA_INTERRUPTION_FILTER,
+ mutableWatchState.interruptionFilter.getValueOr(0)
+ ),
+ extras.getInt(
+ Constants.EXTRA_UNREAD_COUNT,
+ mutableWatchState.unreadNotificationCount.getValueOr(0)
+ ),
+ extras.getInt(
+ Constants.EXTRA_NOTIFICATION_COUNT,
+ mutableWatchState.notificationCount.getValueOr(0)
+ )
+ )
)
val statusBundle = extras.getBundle(Constants.EXTRA_INDICATOR_STATUS)
if (statusBundle != null) {
watchFaceCommand.setIndicatorState(
- statusBundle.getBoolean(Constants.STATUS_CHARGING),
- statusBundle.getBoolean(Constants.STATUS_AIRPLANE_MODE),
- statusBundle.getBoolean(Constants.STATUS_CONNECTED),
- statusBundle.getBoolean(Constants.STATUS_THEATER_MODE),
- statusBundle.getBoolean(Constants.STATUS_GPS_ACTIVE),
- statusBundle.getBoolean(Constants.STATUS_KEYGUARD_LOCKED)
+ IndicatorState(
+ statusBundle.getBoolean(Constants.STATUS_CHARGING),
+ statusBundle.getBoolean(Constants.STATUS_AIRPLANE_MODE),
+ statusBundle.getBoolean(Constants.STATUS_CONNECTED),
+ statusBundle.getBoolean(Constants.STATUS_THEATER_MODE),
+ statusBundle.getBoolean(Constants.STATUS_GPS_ACTIVE),
+ statusBundle.getBoolean(Constants.STATUS_KEYGUARD_LOCKED)
+ )
)
}
@@ -731,7 +788,7 @@
watchFace = createWatchFace(
currentSurfaceHolder,
host,
- systemState
+ mutableWatchState.asWatchState()
)
// Watchfaces especially OpenGL ones often do initialization in
@@ -784,14 +841,22 @@
* intent filter depending on whether we are in ambient mode or not.
*/
internal fun updateTimeTickReceiver() {
+ // Separate calls are issued to deliver the state of isAmbient and isVisible, so during
+ // init we might not yet know the state of both.
+ if (!mutableWatchState.isAmbient.hasValue() ||
+ !mutableWatchState.isVisible.hasValue()
+ ) {
+ return
+ }
+
if (timeTickRegistered) {
unregisterReceiver(timeTickReceiver)
timeTickRegistered = false
}
// We only register if we are visible, otherwise it doesn't make sense to waste cycles.
- if (systemState.isVisible) {
- if (systemState.isAmbient) {
+ if (mutableWatchState.isVisible.value) {
+ if (mutableWatchState.isAmbient.value) {
registerReceiver(timeTickReceiver, ambientTimeTickFilter)
} else {
registerReceiver(timeTickReceiver, interactiveTimeTickFilter)
@@ -824,7 +889,7 @@
return
}
- systemState.onVisibilityChanged(visible)
+ mutableWatchState.isVisible.value = visible
updateTimeTickReceiver()
pendingVisibilityChanged = null
}
@@ -878,8 +943,10 @@
}
watchFaceCommand.setImmutableSystemState(
- properties.getBoolean(Constants.PROPERTY_LOW_BIT_AMBIENT),
- properties.getBoolean(Constants.PROPERTY_BURN_IN_PROTECTION)
+ ImmutableSystemState(
+ properties.getBoolean(Constants.PROPERTY_LOW_BIT_AMBIENT),
+ properties.getBoolean(Constants.PROPERTY_BURN_IN_PROTECTION)
+ )
)
}
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchState.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchState.kt
index e80d7a9..1d3ad2f 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchState.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchState.kt
@@ -16,351 +16,120 @@
package androidx.wear.watchface
-import android.annotation.SuppressLint
-import android.app.NotificationManager
-import androidx.annotation.UiThread
+import androidx.annotation.RestrictTo
-/** An observer for changes in system state which are relevant to watch faces. */
-class WatchState {
- /** The current user interruption settings. See {@link NotificationManager}. */
- var interruptionFilter = NotificationManager.INTERRUPTION_FILTER_ALL
- private set
+class WatchState(
+ /**
+ * The current user interruption settings. See {@link NotificationManager}. Based on the value
+ * the watch face should adjust the amount of information it displays. For example, if it
+ * displays the number of pending emails, it should hide it if interruptionFilter is equal to
+ * {@link NotificationManager.INTERRUPTION_FILTER_NONE}. {@code interruptionFilter} can be
+ * {@link NotificationManager.INTERRUPTION_FILTER_NONE}, {@link
+ * NotificationManager.INTERRUPTION_FILTER_PRIORITY},
+ * {@link NotificationManager.INTERRUPTION_FILTER_ALL},
+ * {@link NotificationManagerINTERRUPTION_FILTER_ALARMS}, or
+ * {@link NotificationManager.INTERRUPTION_FILTER_UNKNOWN}.
+ */
+ val interruptionFilter: WatchData<Int>,
- /** Whether or not the watch is in ambient mode. */
- var isAmbient = false
- private set
+ /**
+ * Whether or not the watch is in ambient mode. The watch face should switch to a simplified low
+ * intensity display when in ambient mode. E.g. if the watch face displays seconds, it should
+ * hide them in ambient mode.
+ */
+ val isAmbient: WatchData<Boolean>,
/**
* Whether or not the watch is in airplane mode. Only valid if
* {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
*/
- @get:JvmName("inAirplaneMode")
- var inAirplaneMode = false
- private set
+ val inAirplaneMode: WatchData<Boolean>,
/**
- * Whether or not we should conserve power due to low battery. Only valid if
- * {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
+ * Whether or not we should conserve power due to a low battery which isn't charging. Only
+ * valid if {@link android.support.wearable.watchface
+ * .WatchFaceStyle#hideNotificationIndicator} is true.
*/
- var isBatteryLowAndNotCharging = false
- private set
+ val isBatteryLowAndNotCharging: WatchData<Boolean>,
/**
* Whether or not the watch is charging. Only valid if
* {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
*/
- var isCharging = false
- private set
+ val isCharging: WatchData<Boolean>,
/**
* Whether or not the watch is connected to the companion phone. Only valid if
* {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
*/
- var isConnectedToCompanion = false
- private set
+ val isConnectedToCompanion: WatchData<Boolean>,
/**
* Whether or not GPS is active on the watch. Only valid if
* {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
*/
- var isGpsActive = false
- private set
+ val isGpsActive: WatchData<Boolean>,
/**
* Whether or not the watch's keyguard (lock screen) is locked. Only valid if
* {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
*/
- var isKeyguardLocked = false
- private set
+ val isKeyguardLocked: WatchData<Boolean>,
/**
* Whether or not the watch is in theater mode. Only valid if
* {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
*/
- var isInTheaterMode = false
- private set
+ val isInTheaterMode: WatchData<Boolean>,
/** Whether or not the watch face is visible. */
- var isVisible = false
- private set
+ val isVisible: WatchData<Boolean>,
/** The total number of notification cards in the stream. */
- var notificationCount = 0
- private set
+ val notificationCount: WatchData<Int>,
/** The total number of unread notification cards in the stream. */
- var unreadNotificationCount = 0
- private set
+ val unreadNotificationCount: WatchData<Int>,
/** Whether or not the watch has low bit ambient support. */
- @get:JvmName("hasLowBitAmbient")
- var hasLowBitAmbient = false
- private set
+ val hasLowBitAmbient: WatchData<Boolean>,
/** Whether or not the watch has burn in protection support. */
- @get:JvmName("hasBurnInProtection")
- var hasBurnInProtection = false
- private set
+ val hasBurnInProtection: WatchData<Boolean>
+)
- private val mListeners = HashSet<Listener>()
+/** @hide */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class MutableWatchState {
+ var interruptionFilter = MutableWatchData<Int>()
+ val isAmbient = MutableWatchData<Boolean>()
+ val inAirplaneMode = MutableWatchData<Boolean>()
+ val isBatteryLowAndNotCharging = MutableWatchData<Boolean>()
+ val isCharging = MutableWatchData<Boolean>()
+ val isConnectedToCompanion = MutableWatchData<Boolean>()
+ val isGpsActive = MutableWatchData<Boolean>()
+ val isKeyguardLocked = MutableWatchData<Boolean>()
+ val isInTheaterMode = MutableWatchData<Boolean>()
+ val isVisible = MutableWatchData<Boolean>()
+ val notificationCount = MutableWatchData<Int>()
+ val unreadNotificationCount = MutableWatchData<Int>()
+ val hasLowBitAmbient = MutableWatchData<Boolean>()
+ val hasBurnInProtection = MutableWatchData<Boolean>()
- interface Listener {
- /**
- * Called when the device enters or exits ambient mode. The watch face should switch to a
- * simplified low intensity display when in ambient mode. E.g. if the watch face displays
- * seconds, it should hide them in ambient mode.
- *
- * @param isAmbient Whether or not the device is in ambient mode
- */
- @UiThread
- fun onAmbientModeChanged(isAmbient: Boolean) {}
-
- /**
- * Called when the device enters or exits airplane mode.
- *
- * @param inAirplaneMode Whether or not the device is in airplane mode
- */
- @UiThread
- fun onInAirplaneModeChanged(inAirplaneMode: Boolean) {}
-
- /**
- * Called when the devices enters or exits a condition where the battery is low and not
- * charging.
- *
- * @param isBatteryLowAndNotCharging Whether or not the battery is low and not charging
- */
- @UiThread
- fun onIsBatteryLowAndNotCharging(isBatteryLowAndNotCharging: Boolean) {}
-
- /**
- * Called when the device starts or stops charging.
- *
- * @param isCharging Whether or not the device is charging
- */
- @UiThread
- fun onIsChargingChanged(isCharging: Boolean) {}
-
- /**
- * Called when the device connects or disconnects with the companion phone.
- *
- * @param isConnectedToCompanion Whether or not the device is connected to the phone
- */
- @UiThread
- fun onIsConnectedToCompanionChanged(isConnectedToCompanion: Boolean) {}
-
- /**
- * Called when GPS is enabled or disabled.
- *
- * @param isGpsActive Whether or not GPS is enabled
- */
- @UiThread
- fun onIsGpsActiveChanged(isGpsActive: Boolean) {}
-
- /**
- * Called when the keyguard (lock screen) is locked or unlocked.
- *
- * @param isKeyguardLocked Whether or not the keyguard (lock screen) is locked
- */
- @UiThread
- fun onIsKeyguardLockedChanged(isKeyguardLocked: Boolean) {}
-
- /**
- * Called when the user changes the interruption filter. The watch face should adjust the amount
- * of information it displays. For example, if it displays the number of pending emails,
- * it should hide it if interruptionFilter is equal to
- * {@link NotificationManager.INTERRUPTION_FILTER_NONE}. {@code interruptionFilter} can be
- * {@link NotificationManager.INTERRUPTION_FILTER_NONE}, {@link
- * NotificationManager.INTERRUPTION_FILTER_PRIORITY},
- * {@link NotificationManager.INTERRUPTION_FILTER_ALL},
- * {@link NotificationManagerINTERRUPTION_FILTER_ALARMS}, or
- * {@link NotificationManager.INTERRUPTION_FILTER_UNKNOWN}.
- *
- * @param interruptionFilter The current interruption filter set by the user
- */
- @UiThread
- fun onInterruptionFilterChanged(interruptionFilter: Int) {}
-
- /**
- * Called when the device enters or exits theater mode.
- *
- * @param inTheaterMode Whether or not the device is in theater mode
- */
- @UiThread
- fun onInTheaterModeChanged(inTheaterMode: Boolean) {}
-
- /**
- * Called when the total number of notification cards in the stream has changed.
- *
- * @param notificationCount total number of the notification cards in the stream
- */
- @UiThread
- fun onNotificationCountChanged(notificationCount: Int) {}
-
- /**
- * Called when the number of unread notification cards in the stream has changed.
- *
- * @param unreadNotificationCount number of the notification cards in the stream that
- * haven't yet been seen by the user
- */
- @UiThread
- fun onUnreadNotificationCountChanged(unreadNotificationCount: Int) {}
-
- /**
- * Called to inform you of the watch face becoming visible or hidden. Note the
- * {@link WatchFace} automatically schedules draw calls as necessary.
- *
- * @param visible Whether the watch face is visible or hidden
- */
- @UiThread
- fun onVisibilityChanged(visible: Boolean) {}
-
- /**
- * Called when we've determined if the device has burn in protection or not.
- *
- * @param hasBurnInProtection Whether or not the device has burn in protection
- */
- @UiThread
- fun onHasBurnInProtectionSet(hasBurnInProtection: Boolean) {}
-
- /**
- * Called when we've determined if the device has a lower bit depth in ambient mode or not.
- *
- * @param hasLowBitAmbient Whether or not the device has a lower bit depth in ambient mode
- */
- @UiThread
- fun onHasLowBitAmbientSet(hasLowBitAmbient: Boolean) {}
- }
-
- /**
- * Adds a {@link Listener} which will be called every time the system state changes.
- *
- * @param listener The {@link Listener} to add
- */
- @UiThread
- @SuppressLint("ExecutorRegistration")
- fun addListener(listener: Listener) {
- mListeners.add(listener)
- }
-
- /**
- * Removes a {@link Listener} previously added by {@link addListener}.
- *
- * @param listener The {@link #Listener} to remove
- */
- @UiThread
- fun removeListener(listener: Listener) {
- mListeners.remove(listener)
- }
-
- @UiThread
- internal fun onAmbientModeChanged(isAmbient: Boolean) {
- this.isAmbient = isAmbient
- for (listener in mListeners) {
- listener.onAmbientModeChanged(isAmbient)
- }
- }
-
- @UiThread
- internal fun onInAirplaneModeChanged(inAirplaneMode: Boolean) {
- this.inAirplaneMode = inAirplaneMode
- for (listener in mListeners) {
- listener.onInAirplaneModeChanged(inAirplaneMode)
- }
- }
-
- @UiThread
- internal fun onIsBatteryLowAndNotCharging(isBatteryLowAndNotCharging: Boolean) {
- this.isBatteryLowAndNotCharging = isBatteryLowAndNotCharging
- for (listener in mListeners) {
- listener.onIsBatteryLowAndNotCharging(isBatteryLowAndNotCharging)
- }
- }
-
- @UiThread
- internal fun onIsChargingChanged(isCharging: Boolean) {
- this.isCharging = isCharging
- for (listener in mListeners) {
- listener.onIsChargingChanged(isCharging)
- }
- }
-
- @UiThread
- internal fun onIsConnectedToCompanionChanged(isConnectedToCompanion: Boolean) {
- this.isConnectedToCompanion = isConnectedToCompanion
- for (listener in mListeners) {
- listener.onIsConnectedToCompanionChanged(isConnectedToCompanion)
- }
- }
-
- @UiThread
- internal fun onIsGpsActiveChanged(isGpsActive: Boolean) {
- this.isGpsActive = isGpsActive
- for (listener in mListeners) {
- listener.onIsGpsActiveChanged(isGpsActive)
- }
- }
-
- @UiThread
- internal fun onIsKeyguardLockedChanged(isKeyguardLocked: Boolean) {
- this.isKeyguardLocked = isKeyguardLocked
- for (listener in mListeners) {
- listener.onIsKeyguardLockedChanged(isKeyguardLocked)
- }
- }
-
- @UiThread
- internal fun onInterruptionFilterChanged(interruptionFilter: Int) {
- this.interruptionFilter = interruptionFilter
- for (listener in mListeners) {
- listener.onInterruptionFilterChanged(interruptionFilter)
- }
- }
-
- @UiThread
- internal fun onInTheaterModeChanged(inTheaterMode: Boolean) {
- this.isInTheaterMode = inTheaterMode
- for (listener in mListeners) {
- listener.onInTheaterModeChanged(inTheaterMode)
- }
- }
-
- @UiThread
- internal fun onNotificationCountChanged(notificationCount: Int) {
- this.notificationCount = notificationCount
- for (listener in mListeners) {
- listener.onNotificationCountChanged(notificationCount)
- }
- }
-
- @UiThread
- internal fun onUnreadNotificationCountChanged(unreadNotificationCount: Int) {
- this.unreadNotificationCount = unreadNotificationCount
- for (listener in mListeners) {
- listener.onUnreadNotificationCountChanged(unreadNotificationCount)
- }
- }
-
- @UiThread
- internal fun onVisibilityChanged(visible: Boolean) {
- this.isVisible = visible
- for (listener in mListeners) {
- listener.onVisibilityChanged(visible)
- }
- }
-
- @UiThread
- internal fun setHasBurnInProtection(hasBurnInProtection: Boolean) {
- this.hasBurnInProtection = hasBurnInProtection
- for (listener in mListeners) {
- listener.onHasBurnInProtectionSet(hasBurnInProtection)
- }
- }
-
- @UiThread
- internal fun setHasLowBitAmbient(hasLowBitAmbient: Boolean) {
- this.hasLowBitAmbient = hasLowBitAmbient
- for (listener in mListeners) {
- listener.onHasLowBitAmbientSet(hasLowBitAmbient)
- }
- }
-}
+ fun asWatchState() = WatchState(
+ interruptionFilter = interruptionFilter,
+ isAmbient = isAmbient,
+ inAirplaneMode = inAirplaneMode,
+ isBatteryLowAndNotCharging = isBatteryLowAndNotCharging,
+ isCharging = isCharging,
+ isConnectedToCompanion = isConnectedToCompanion,
+ isGpsActive = isGpsActive,
+ isKeyguardLocked = isKeyguardLocked,
+ isInTheaterMode = isInTheaterMode,
+ isVisible = isVisible,
+ notificationCount = notificationCount,
+ unreadNotificationCount = unreadNotificationCount,
+ hasLowBitAmbient = hasLowBitAmbient,
+ hasBurnInProtection = hasBurnInProtection
+ )
+}
\ No newline at end of file
diff --git a/wear/wear-watchface/src/test/java/androidx/wear/watchface/TestCommon.kt b/wear/wear-watchface/src/test/java/androidx/wear/watchface/TestCommon.kt
index 013eb3c..d5e3e1c 100644
--- a/wear/wear-watchface/src/test/java/androidx/wear/watchface/TestCommon.kt
+++ b/wear/wear-watchface/src/test/java/androidx/wear/watchface/TestCommon.kt
@@ -37,12 +37,12 @@
import org.robolectric.RobolectricTestRunner
import org.robolectric.internal.bytecode.InstrumentationConfiguration
-class TestWatchFaceService(
+internal class TestWatchFaceService(
@WatchFaceType private val watchFaceType: Int,
private val complicationsManager: ComplicationsManager,
private val renderer: TestRenderer,
private val userStyleRepository: UserStyleRepository,
- private val watchState: WatchState,
+ private val watchState: MutableWatchState,
private val handler: Handler,
private val interactiveFrameRateMs: Long
) : WatchFaceService() {
@@ -116,7 +116,7 @@
override fun getHandler() = handler
- override fun getSystemState() = watchState
+ override fun getMutableWatchState() = watchState
}
/**
diff --git a/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchDataTest.kt b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchDataTest.kt
new file mode 100644
index 0000000..bfc377d
--- /dev/null
+++ b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchDataTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2020 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 androidx.wear.watchface
+
+import androidx.lifecycle.Observer
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.any
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.robolectric.annotation.Config
+
+@Config(manifest = Config.NONE)
+@RunWith(WatchFaceTestRunner::class)
+class WatchDataTest {
+ @Mock
+ private lateinit var observer: Observer<Int>
+
+ @Mock
+ private lateinit var observer2: Observer<Int>
+
+ @Mock
+ private lateinit var observer3: Observer<Int>
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun initialValue() {
+ val data = MutableWatchData(10)
+ assertThat(data.value).isEqualTo(10)
+ }
+
+ @Test
+ fun mutatedValue() {
+ val data = MutableWatchData(10)
+ data.value = 20
+ assertThat(data.value).isEqualTo(20)
+ }
+
+ @Test
+ fun addObserverNoData() {
+ val data = MutableWatchData<Int>()
+ data.observe(observer)
+ verify(observer, never()).onChanged(any())
+ }
+
+ @Test
+ fun addObserver() {
+ val data = MutableWatchData(10)
+ data.observe(observer)
+ verify(observer).onChanged(10)
+ }
+
+ @Test
+ fun addObserverAndAssign() {
+ val data = MutableWatchData(10)
+ data.observe(observer)
+ verify(observer).onChanged(10)
+
+ data.value = 20
+ verify(observer).onChanged(20)
+ }
+
+ @Test
+ fun addObserverNoDataThenAssign() {
+ val data = MutableWatchData<Int>()
+ data.observe(observer)
+
+ data.value = 20
+ verify(observer).onChanged(20)
+ }
+
+ @Test
+ fun addAndRemoveObserver() {
+ val data = MutableWatchData(10)
+ data.observe(observer)
+ data.removeObserver(observer)
+ verify(observer).onChanged(10)
+
+ data.value = 20
+ verify(observer, never()).onChanged(20)
+ }
+
+ @Test
+ fun removeObserverDuringCallback() {
+ val data = MutableWatchData(10)
+ data.observe(observer)
+ data.observe(observer2)
+ data.observe(observer3)
+
+ verify(observer).onChanged(10)
+ verify(observer2).onChanged(10)
+ verify(observer3).onChanged(10)
+
+ // Remove observer2 when observer invoked
+ Mockito.doAnswer {
+ data.removeObserver(observer2)
+ }.`when`(observer).onChanged(20)
+
+ data.value = 20
+ verify(observer2, never()).onChanged(20)
+ verify(observer3).onChanged(20)
+ }
+}
\ No newline at end of file
diff --git a/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
index 7b14533..59edbee 100644
--- a/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
+++ b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
@@ -32,6 +32,7 @@
import android.support.wearable.watchface.accessibility.ContentDescriptionLabel
import android.view.SurfaceHolder
import android.view.ViewConfiguration
+import androidx.lifecycle.Observer
import androidx.test.core.app.ApplicationProvider
import androidx.wear.complications.SystemProviders
import androidx.wear.complications.rendering.ComplicationDrawable
@@ -40,6 +41,7 @@
import androidx.wear.watchface.style.UserStyleCategory
import androidx.wear.watchface.style.UserStyleRepository
import com.google.common.truth.Truth.assertThat
+import com.nhaarman.mockitokotlin2.mock
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -50,7 +52,6 @@
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mockito.`when`
import org.mockito.Mockito.doAnswer
-import org.mockito.Mockito.mock
import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.validateMockitoUsage
@@ -68,10 +69,10 @@
@RunWith(WatchFaceTestRunner::class)
class WatchFaceServiceTest {
- private val handler = mock(Handler::class.java)
- private val iWatchFaceService = mock(IWatchFaceService::class.java)
- private val surfaceHolder = mock(SurfaceHolder::class.java)
- private val systemState = WatchState()
+ private val handler = mock<Handler>()
+ private val iWatchFaceService = mock<IWatchFaceService>()
+ private val surfaceHolder = mock<SurfaceHolder>()
+ private val watchState = MutableWatchState()
init {
`when`(surfaceHolder.surfaceFrame).thenReturn(ONE_HUNDRED_BY_ONE_HUNDRED_RECT)
@@ -101,7 +102,8 @@
"Colors",
"Watchface colorization", /* icon = */
null,
- colorStyleList
+ colorStyleList,
+ UserStyleCategory.LAYER_WATCH_FACE_BASE
)
private val classicStyleOption =
@@ -121,7 +123,8 @@
"Hand Style",
"Hand visual look", /* icon = */
null,
- watchHandStyleList
+ watchHandStyleList,
+ UserStyleCategory.LAYER_WATCH_FACE_UPPER
)
private val badStyleOption =
@@ -130,7 +133,10 @@
private val leftComplication =
Complication.Builder(
LEFT_COMPLICATION_ID,
- ComplicationDrawableRenderer(complicationDrawableLeft, systemState).apply {
+ ComplicationDrawableRenderer(
+ complicationDrawableLeft,
+ watchState.asWatchState()
+ ).apply {
setData(createComplicationData())
},
intArrayOf(
@@ -148,7 +154,10 @@
private val rightComplication =
Complication.Builder(
RIGHT_COMPLICATION_ID,
- ComplicationDrawableRenderer(complicationDrawableRight, systemState).apply {
+ ComplicationDrawableRenderer(
+ complicationDrawableRight,
+ watchState.asWatchState()
+ ).apply {
setData(createComplicationData())
},
intArrayOf(
@@ -166,7 +175,10 @@
private val backgroundComplication =
Complication.Builder(
BACKGROUND_COMPLICATION_ID,
- ComplicationDrawableRenderer(complicationDrawableRight, systemState).apply {
+ ComplicationDrawableRenderer(
+ complicationDrawableRight,
+ watchState.asWatchState()
+ ).apply {
setData(createComplicationData())
},
intArrayOf(
@@ -209,13 +221,13 @@
this.complicationsManager = ComplicationsManager(complications)
userStyleRepository =
UserStyleRepository(userStyleCategories)
- renderer = TestRenderer(surfaceHolder, userStyleRepository, systemState)
+ renderer = TestRenderer(surfaceHolder, userStyleRepository, watchState.asWatchState())
testWatchFaceService = TestWatchFaceService(
watchFaceType,
this.complicationsManager,
renderer,
userStyleRepository,
- systemState,
+ watchState,
handler,
INTERACTIVE_UPDATE_RATE_MS
)
@@ -288,45 +300,43 @@
@Test
fun maybeUpdateDrawMode_setsCorrectDrawMode() {
initEngine(WatchFaceType.ANALOG, listOf(leftComplication, rightComplication), emptyList())
+ watchState.isAmbient.value = false
assertThat(renderer.drawMode).isEqualTo(DrawMode.INTERACTIVE)
- systemState.onIsBatteryLowAndNotCharging(true)
+ watchState.isBatteryLowAndNotCharging.value = true
watchFace.maybeUpdateDrawMode()
assertThat(renderer.drawMode).isEqualTo(DrawMode.LOW_BATTERY_INTERACTIVE)
- systemState.onIsBatteryLowAndNotCharging(false)
- systemState.onAmbientModeChanged(true)
+ watchState.isBatteryLowAndNotCharging.value = false
+ watchState.isAmbient.value = true
watchFace.maybeUpdateDrawMode()
assertThat(renderer.drawMode).isEqualTo(DrawMode.AMBIENT)
- systemState.onAmbientModeChanged(false)
+ watchState.isAmbient.value = false
watchFace.maybeUpdateDrawMode()
assertThat(renderer.drawMode).isEqualTo(DrawMode.INTERACTIVE)
- systemState.onInterruptionFilterChanged(
- NotificationManager.INTERRUPTION_FILTER_NONE
- )
+ watchState.interruptionFilter.value = NotificationManager.INTERRUPTION_FILTER_NONE
watchFace.maybeUpdateDrawMode()
assertThat(renderer.drawMode).isEqualTo(DrawMode.MUTE)
// Ambient takes precidence over interruption filter.
- systemState.onAmbientModeChanged(true)
+ watchState.isAmbient.value = true
watchFace.maybeUpdateDrawMode()
assertThat(renderer.drawMode).isEqualTo(DrawMode.AMBIENT)
- systemState.onAmbientModeChanged(false)
- systemState.onInterruptionFilterChanged(0)
+ watchState.isAmbient.value = false
+ watchState.interruptionFilter.value = 0
watchFace.maybeUpdateDrawMode()
assertThat(renderer.drawMode).isEqualTo(DrawMode.INTERACTIVE)
-
- // WatchFaceService.DrawMode.COMPLICATION_SELECT is tested below.
}
@Test
fun onDraw_calendar_setFromSystemTime() {
initEngine(WatchFaceType.ANALOG, listOf(leftComplication, rightComplication), emptyList())
+ watchState.isAmbient.value = false
testWatchFaceService.mockSystemTimeMillis = 1000L
watchFace.onDraw()
assertThat(watchFace.calendar.timeInMillis).isEqualTo(1000L)
@@ -335,6 +345,7 @@
@Test
fun onDraw_calendar_affectedCorrectly_with2xMockTime() {
initEngine(WatchFaceType.ANALOG, listOf(leftComplication, rightComplication), emptyList())
+ watchState.isAmbient.value = false
testWatchFaceService.mockSystemTimeMillis = 1000L
watchFace.mockTimeReceiver.onReceive(
@@ -358,6 +369,7 @@
@Test
fun onDraw_calendar_affectedCorrectly_withMockTimeWrapping() {
initEngine(WatchFaceType.ANALOG, listOf(leftComplication, rightComplication), emptyList())
+ watchState.isAmbient.value = false
testWatchFaceService.mockSystemTimeMillis = 1000L
watchFace.mockTimeReceiver.onReceive(
@@ -738,13 +750,14 @@
listOf(colorStyleCategory, watchHandStyleCategory)
)
- val testRenderer2 = TestRenderer(surfaceHolder, userStyleRepository2, systemState)
+ val testRenderer2 =
+ TestRenderer(surfaceHolder, userStyleRepository2, watchState.asWatchState())
val service2 = TestWatchFaceService(
WatchFaceType.ANALOG,
ComplicationsManager(emptyList()),
testRenderer2,
userStyleRepository2,
- systemState,
+ watchState,
handler,
INTERACTIVE_UPDATE_RATE_MS
)
@@ -793,13 +806,14 @@
listOf(colorStyleCategory, watchHandStyleCategory)
)
- val testRenderer2 = TestRenderer(surfaceHolder, userStyleRepository2, systemState)
+ val testRenderer2 =
+ TestRenderer(surfaceHolder, userStyleRepository2, watchState.asWatchState())
val service2 = TestWatchFaceService(
WatchFaceType.ANALOG,
ComplicationsManager(emptyList()),
testRenderer2,
userStyleRepository2,
- systemState,
+ watchState,
handler,
INTERACTIVE_UPDATE_RATE_MS
)
@@ -837,6 +851,7 @@
@Test
fun maybeUpdateStatus_issuesCorrectApiCalls() {
initEngine(WatchFaceType.ANALOG, emptyList(), emptyList())
+
val bundle = Bundle().apply {
putBoolean(Constants.STATUS_CHARGING, true)
putBoolean(Constants.STATUS_AIRPLANE_MODE, false)
@@ -846,34 +861,49 @@
putBoolean(Constants.STATUS_KEYGUARD_LOCKED, false)
}
- val systemStateListener = mock(WatchState.Listener::class.java)
- systemState.addListener(systemStateListener)
+ val isChargingObserver = mock<Observer<Boolean>>()
+ val inAirplaneModeObserver = mock<Observer<Boolean>>()
+ val isConnectedToCompanionObserver = mock<Observer<Boolean>>()
+ val isInTheaterModeObserver = mock<Observer<Boolean>>()
+ val isGpsActiveObserver = mock<Observer<Boolean>>()
+ val isKeyguardLockedObserver = mock<Observer<Boolean>>()
+ watchState.isCharging.observe(isChargingObserver)
+ watchState.inAirplaneMode.observe(inAirplaneModeObserver)
+ watchState.isConnectedToCompanion.observe(isConnectedToCompanionObserver)
+ watchState.isInTheaterMode.observe(isInTheaterModeObserver)
+ watchState.isGpsActive.observe(isGpsActiveObserver)
+ watchState.isKeyguardLocked.observe(isKeyguardLockedObserver)
// Every indicator onXyz method should be called upon the initial update.
engineWrapper.onBackgroundAction(Bundle().apply {
putBundle(Constants.EXTRA_INDICATOR_STATUS, bundle)
})
- verify(systemStateListener).onIsChargingChanged(true)
- verify(systemStateListener).onInAirplaneModeChanged(false)
- verify(systemStateListener).onIsConnectedToCompanionChanged(true)
- verify(systemStateListener).onInTheaterModeChanged(false)
- verify(systemStateListener).onIsGpsActiveChanged(true)
- verify(systemStateListener).onIsKeyguardLockedChanged(false)
+ verify(isChargingObserver).onChanged(true)
+ verify(inAirplaneModeObserver).onChanged(false)
+ verify(isConnectedToCompanionObserver).onChanged(true)
+ verify(isInTheaterModeObserver).onChanged(false)
+ verify(isGpsActiveObserver).onChanged(true)
+ verify(isKeyguardLockedObserver).onChanged(false)
- reset(systemStateListener)
+ reset(isChargingObserver)
+ reset(inAirplaneModeObserver)
+ reset(isConnectedToCompanionObserver)
+ reset(isInTheaterModeObserver)
+ reset(isGpsActiveObserver)
+ reset(isKeyguardLockedObserver)
// Check only the modified setIsCharging state leads to a call.
bundle.putBoolean(Constants.STATUS_CHARGING, false)
engineWrapper.onBackgroundAction(Bundle().apply {
putBundle(Constants.EXTRA_INDICATOR_STATUS, bundle)
})
- verify(systemStateListener).onIsChargingChanged(false)
- verify(systemStateListener, times(0)).onInAirplaneModeChanged(anyBoolean())
- verify(systemStateListener, times(0)).onIsConnectedToCompanionChanged(anyBoolean())
- verify(systemStateListener, times(0)).onInTheaterModeChanged(anyBoolean())
- verify(systemStateListener, times(0)).onIsGpsActiveChanged(anyBoolean())
- verify(systemStateListener, times(0)).onIsKeyguardLockedChanged(anyBoolean())
+ verify(isChargingObserver).onChanged(false)
+ verify(inAirplaneModeObserver, times(0)).onChanged(anyBoolean())
+ verify(isConnectedToCompanionObserver, times(0)).onChanged(anyBoolean())
+ verify(isInTheaterModeObserver, times(0)).onChanged(anyBoolean())
+ verify(isGpsActiveObserver, times(0)).onChanged(anyBoolean())
+ verify(isKeyguardLockedObserver, times(0)).onChanged(anyBoolean())
}
@Test
@@ -884,13 +914,15 @@
putBoolean(Constants.PROPERTY_BURN_IN_PROTECTION, false)
}
- val systemStateListener = mock(WatchState.Listener::class.java)
- systemState.addListener(systemStateListener)
+ val hasLowBitAmbientObserver = mock<Observer<Boolean>>()
+ val hasBurnInProtectionObserver = mock<Observer<Boolean>>()
+ watchState.hasLowBitAmbient.observe(hasLowBitAmbientObserver)
+ watchState.hasBurnInProtection.observe(hasBurnInProtectionObserver)
// Check all the right methods are called on initial onPropertiesChanged call.
engineWrapper.onPropertiesChanged(bundle)
- verify(systemStateListener).onHasLowBitAmbientSet(true)
- verify(systemStateListener).onHasBurnInProtectionSet(false)
+ verify(hasLowBitAmbientObserver).onChanged(true)
+ verify(hasBurnInProtectionObserver).onChanged(false)
}
@Test
@@ -958,13 +990,40 @@
backgroundComplication.enabled = false
runPostedTasksFor(0)
+ verify(iWatchFaceService).setActiveComplications(
+ intArrayOf(rightComplication.id),
+ true
+ )
+
// Despite disabling the background complication we should still get a
// ContentDescriptionLabel for the main clock element.
val argument = ArgumentCaptor.forClass(Array<ContentDescriptionLabel>::class.java)
verify(iWatchFaceService).setContentDescriptionLabels(argument.capture())
assertThat(argument.value.size).isEqualTo(2)
assertThat(argument.value[0].bounds).isEqualTo(Rect(25, 25, 75, 75)) // Clock element.
- assertThat(argument.value[1].bounds).isEqualTo(Rect(60, 40, 80, 60)) // Right complicaiton.
+ assertThat(argument.value[1].bounds).isEqualTo(Rect(60, 40, 80, 60)) // Right complication.
+ }
+
+ @Test
+ fun moveComplications() {
+ initEngine(WatchFaceType.ANALOG, listOf(leftComplication, rightComplication), emptyList())
+
+ // Ignore initial setContentDescriptionLabels call.
+ reset(iWatchFaceService)
+
+ leftComplication.unitSquareBounds = RectF(0.3f, 0.3f, 0.5f, 0.5f)
+ rightComplication.unitSquareBounds = RectF(0.7f, 0.75f, 0.9f, 0.95f)
+
+ runPostedTasksFor(0)
+
+ // Despite disabling the background complication we should still get a
+ // ContentDescriptionLabel for the main clock element.
+ val argument = ArgumentCaptor.forClass(Array<ContentDescriptionLabel>::class.java)
+ verify(iWatchFaceService).setContentDescriptionLabels(argument.capture())
+ assertThat(argument.value.size).isEqualTo(3)
+ assertThat(argument.value[0].bounds).isEqualTo(Rect(25, 25, 75, 75)) // Clock element.
+ assertThat(argument.value[1].bounds).isEqualTo(Rect(30, 30, 50, 50)) // Left complication.
+ assertThat(argument.value[2].bounds).isEqualTo(Rect(70, 75, 90, 95)) // Right complication.
}
@Test
@@ -1003,7 +1062,8 @@
fun requestStyleBeforeSetBinder() {
var userStyleRepository =
UserStyleRepository(emptyList())
- var testRenderer = TestRenderer(surfaceHolder, userStyleRepository, systemState)
+ var testRenderer =
+ TestRenderer(surfaceHolder, userStyleRepository, watchState.asWatchState())
val service = TestWatchFaceService(
WatchFaceType.ANALOG,
ComplicationsManager(
@@ -1011,7 +1071,7 @@
),
testRenderer,
UserStyleRepository(emptyList()),
- systemState,
+ watchState,
handler,
INTERACTIVE_UPDATE_RATE_MS
)
@@ -1036,7 +1096,7 @@
val provider2 = ComponentName("com.app2", "com.app2.App2")
val complication = Complication.Builder(
LEFT_COMPLICATION_ID,
- ComplicationDrawableRenderer(complicationDrawableLeft, systemState),
+ ComplicationDrawableRenderer(complicationDrawableLeft, watchState.asWatchState()),
intArrayOf(),
Complication.DefaultComplicationProviderPolicy(
listOf(provider1, provider2),
@@ -1061,7 +1121,7 @@
val provider2 = ComponentName("com.app2", "com.app2.App2")
val complication = Complication.Builder(
LEFT_COMPLICATION_ID,
- ComplicationDrawableRenderer(complicationDrawableLeft, systemState),
+ ComplicationDrawableRenderer(complicationDrawableLeft, watchState.asWatchState()),
intArrayOf(),
Complication.DefaultComplicationProviderPolicy(
listOf(provider1, provider2),
@@ -1098,7 +1158,8 @@
@Test
fun shouldAnimateOverrideControlsEnteringAmbientMode() {
var userStyleRepository = UserStyleRepository(emptyList())
- var testRenderer = object : TestRenderer(surfaceHolder, userStyleRepository, systemState) {
+ var testRenderer = object :
+ TestRenderer(surfaceHolder, userStyleRepository, watchState.asWatchState()) {
var animate = true
override fun shouldAnimate() = animate
}
@@ -1107,7 +1168,7 @@
ComplicationsManager(emptyList()),
testRenderer,
UserStyleRepository(emptyList()),
- systemState,
+ watchState,
handler,
INTERACTIVE_UPDATE_RATE_MS
)
@@ -1122,7 +1183,7 @@
watchFace = service.watchFace
// Enter ambient mode.
- systemState.onAmbientModeChanged(true)
+ watchState.isAmbient.value = true
watchFace.maybeUpdateDrawMode()
assertThat(testRenderer.drawMode).isEqualTo(DrawMode.INTERACTIVE)
diff --git a/wear/wear-watchface/src/test/java/androidx/wear/watchface/ui/WatchFaceConfigUiTest.kt b/wear/wear-watchface/src/test/java/androidx/wear/watchface/ui/WatchFaceConfigUiTest.kt
index 48e42a3..cc60e3f 100644
--- a/wear/wear-watchface/src/test/java/androidx/wear/watchface/ui/WatchFaceConfigUiTest.kt
+++ b/wear/wear-watchface/src/test/java/androidx/wear/watchface/ui/WatchFaceConfigUiTest.kt
@@ -31,9 +31,9 @@
import androidx.wear.watchface.Complication
import androidx.wear.watchface.ComplicationDrawableRenderer
import androidx.wear.watchface.ComplicationsManager
+import androidx.wear.watchface.MutableWatchState
import androidx.wear.watchface.Renderer
import androidx.wear.watchface.WatchFaceTestRunner
-import androidx.wear.watchface.WatchState
import androidx.wear.watchface.createComplicationData
import androidx.wear.watchface.style.ListUserStyleCategory
import androidx.wear.watchface.style.StyleUtils
@@ -66,7 +66,7 @@
private val watchFaceConfigDelegate = Mockito.mock(WatchFaceConfigDelegate::class.java)
private val fragmentController = Mockito.mock(FragmentController::class.java)
private val surfaceHolder = Mockito.mock(SurfaceHolder::class.java)
- private val systemState = WatchState()
+ private val watchState = MutableWatchState()
private val context: Context = ApplicationProvider.getApplicationContext()
private val complicationDrawableLeft = ComplicationDrawable(context)
@@ -88,7 +88,8 @@
"Colors",
"Watchface colorization", /* icon = */
null,
- colorStyleList
+ colorStyleList,
+ UserStyleCategory.LAYER_WATCH_FACE_BASE
)
private val classicStyleOption =
@@ -108,13 +109,17 @@
"Hand Style",
"Hand visual look", /* icon = */
null,
- watchHandStyleList
+ watchHandStyleList,
+ UserStyleCategory.LAYER_WATCH_FACE_UPPER
)
private val leftComplication =
Complication.Builder(
LEFT_COMPLICATION_ID,
- ComplicationDrawableRenderer(complicationDrawableLeft, systemState).apply {
+ ComplicationDrawableRenderer(
+ complicationDrawableLeft,
+ watchState.asWatchState()
+ ).apply {
setData(createComplicationData())
},
intArrayOf(
@@ -132,7 +137,10 @@
private val rightComplication =
Complication.Builder(
RIGHT_COMPLICATION_ID,
- ComplicationDrawableRenderer(complicationDrawableRight, systemState).apply {
+ ComplicationDrawableRenderer(
+ complicationDrawableRight,
+ watchState.asWatchState()
+ ).apply {
setData(createComplicationData())
},
intArrayOf(
@@ -150,7 +158,10 @@
private val backgroundComplication =
Complication.Builder(
BACKGROUND_COMPLICATION_ID,
- ComplicationDrawableRenderer(complicationDrawableRight, systemState).apply {
+ ComplicationDrawableRenderer(
+ complicationDrawableRight,
+ watchState.asWatchState()
+ ).apply {
setData(createComplicationData())
},
intArrayOf(
@@ -181,7 +192,7 @@
val complicationSet = ComplicationsManager(
complications,
- object : Renderer(surfaceHolder, userStyleRepository, WatchState()) {
+ object : Renderer(surfaceHolder, userStyleRepository, watchState.asWatchState()) {
override fun renderInternal(calendar: Calendar) {}
override fun takeScreenshot(calendar: Calendar, drawMode: Int): Bitmap {
diff --git a/work/workmanager-multiprocess/proguard-rules.pro b/work/workmanager-multiprocess/proguard-rules.pro
index e69de29..40111ea 100644
--- a/work/workmanager-multiprocess/proguard-rules.pro
+++ b/work/workmanager-multiprocess/proguard-rules.pro
@@ -0,0 +1,4 @@
+# This is necessary so that RemoteWorkManager can be initialized (also marked with @Keep)
+-keep class androidx.work.multiprocess.RemoteWorkManagerClient {
+ public <init>(...);
+}
diff --git a/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkContinuationImpl.java b/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkContinuationImpl.java
index 5d03a5f..4acdf02 100644
--- a/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkContinuationImpl.java
+++ b/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkContinuationImpl.java
@@ -19,6 +19,7 @@
import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkContinuation;
@@ -29,7 +30,10 @@
/**
* An implementation of {@link RemoteWorkContinuation}.
+ *
+ * @hide
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class RemoteWorkContinuationImpl extends RemoteWorkContinuation {
private final RemoteWorkManagerClient mClient;
private final WorkContinuation mContinuation;
diff --git a/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkManagerClient.java b/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkManagerClient.java
index 78a990b..1ebb4e4 100644
--- a/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkManagerClient.java
+++ b/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkManagerClient.java
@@ -28,6 +28,7 @@
import android.os.IBinder;
import android.os.RemoteException;
+import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
@@ -76,6 +77,7 @@
private Session mSession;
+ @Keep
public RemoteWorkManagerClient(@NonNull Context context, @NonNull WorkManagerImpl workManager) {
mContext = context.getApplicationContext();
mWorkManager = workManager;
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt b/work/workmanager/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
index de134fa..e4109c6 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
@@ -40,6 +40,7 @@
import androidx.work.impl.foreground.SystemForegroundDispatcher.createCancelWorkIntent
import androidx.work.impl.foreground.SystemForegroundDispatcher.createNotifyIntent
import androidx.work.impl.foreground.SystemForegroundDispatcher.createStartForegroundIntent
+import androidx.work.impl.foreground.SystemForegroundDispatcher.createStopForegroundIntent
import androidx.work.impl.utils.StopWorkRunnable
import androidx.work.impl.utils.SynchronousExecutor
import androidx.work.impl.utils.taskexecutor.InstantWorkTaskExecutor
@@ -54,6 +55,7 @@
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
+import org.mockito.Mockito.reset
import org.mockito.Mockito.spy
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@@ -141,7 +143,7 @@
fun testStopForeground() {
// The Foreground Service now calls handleStop() directly without the need for an
// additional startService().
- dispatcher.handleStop()
+ dispatcher.handleStop(createStopForegroundIntent(context))
verify(dispatcherCallback, times(1)).stop()
}
@@ -200,7 +202,7 @@
verify(dispatcherCallback, times(1))
.cancelNotification(secondId)
assertThat(dispatcher.mForegroundInfoById.count(), `is`(1))
-
+ reset(dispatcherCallback)
dispatcher.onExecuted(secondWorkSpecId, false)
verify(dispatcherCallback, times(1))
.cancelNotification(secondId)
diff --git a/work/workmanager/src/main/java/androidx/work/impl/Processor.java b/work/workmanager/src/main/java/androidx/work/impl/Processor.java
index ed88dec..129294d 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/Processor.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/Processor.java
@@ -16,6 +16,7 @@
package androidx.work.impl;
import static androidx.work.impl.foreground.SystemForegroundDispatcher.createStartForegroundIntent;
+import static androidx.work.impl.foreground.SystemForegroundDispatcher.createStopForegroundIntent;
import android.content.Context;
import android.content.Intent;
@@ -30,7 +31,6 @@
import androidx.work.Logger;
import androidx.work.WorkerParameters;
import androidx.work.impl.foreground.ForegroundProcessor;
-import androidx.work.impl.foreground.SystemForegroundService;
import androidx.work.impl.utils.WakeLocks;
import androidx.work.impl.utils.taskexecutor.TaskExecutor;
@@ -308,15 +308,8 @@
synchronized (mLock) {
boolean hasForegroundWork = !mForegroundWorkMap.isEmpty();
if (!hasForegroundWork) {
- final SystemForegroundService instance = SystemForegroundService.getInstance();
- if (instance != null) {
- Logger.get().debug(TAG,
- "No more foreground work. Stopping SystemForegroundService");
- instance.stopForegroundService();
- } else {
- Logger.get().debug(TAG,
- "No more foreground work. SystemForegroundService is already stopped");
- }
+ Intent intent = createStopForegroundIntent(mAppContext);
+ mAppContext.startService(intent);
// Release wake lock if there is no more pending work.
if (mForegroundLock != null) {
mForegroundLock.release();
diff --git a/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundDispatcher.java b/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundDispatcher.java
index 8478d84..fcfea94 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundDispatcher.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundDispatcher.java
@@ -71,6 +71,7 @@
private static final String ACTION_START_FOREGROUND = "ACTION_START_FOREGROUND";
private static final String ACTION_NOTIFY = "ACTION_NOTIFY";
private static final String ACTION_CANCEL_WORK = "ACTION_CANCEL_WORK";
+ private static final String ACTION_STOP_FOREGROUND = "ACTION_STOP_FOREGROUND";
private Context mContext;
private WorkManagerImpl mWorkManagerImpl;
@@ -84,9 +85,6 @@
String mCurrentForegroundWorkSpecId;
@SuppressWarnings("WeakerAccess") // Synthetic access
- ForegroundInfo mLastForegroundInfo;
-
- @SuppressWarnings("WeakerAccess") // Synthetic access
final Map<String, ForegroundInfo> mForegroundInfoById;
@SuppressWarnings("WeakerAccess") // Synthetic access
@@ -107,7 +105,6 @@
mWorkManagerImpl = WorkManagerImpl.getInstance(mContext);
mTaskExecutor = mWorkManagerImpl.getWorkTaskExecutor();
mCurrentForegroundWorkSpecId = null;
- mLastForegroundInfo = null;
mForegroundInfoById = new LinkedHashMap<>();
mTrackedWorkSpecs = new HashSet<>();
mWorkSpecById = new HashMap<>();
@@ -148,8 +145,8 @@
}
}
+ ForegroundInfo removedInfo = mForegroundInfoById.remove(workSpecId);
// Promote new notifications to the foreground if necessary.
- mLastForegroundInfo = mForegroundInfoById.remove(workSpecId);
if (workSpecId.equals(mCurrentForegroundWorkSpecId)) {
if (mForegroundInfoById.size() > 0) {
// Find the next eligible ForegroundInfo
@@ -178,9 +175,23 @@
mCallback.cancelNotification(info.getNotificationId());
}
}
- } else if (mLastForegroundInfo != null && mCallback != null) {
+ }
+ if (removedInfo != null && mCallback != null) {
// Explicitly decrement the reference count for the notification
- mCallback.cancelNotification(mLastForegroundInfo.getNotificationId());
+
+ // We are doing this without having to wait for the handleStop() to clean up
+ // Notifications. This is because the Processor stops foreground workers on the
+ // dedicated task executor thread. Meanwhile Notifications are managed on the main
+ // thread, so there is a chance that handleStop() fires before onExecuted() is called
+ // on the main thread.
+ Logger.get().debug(TAG,
+ String.format("Removing Notification (id: %s, workSpecId: %s ,"
+ + "notificationType: %s)",
+ removedInfo.getNotificationId(),
+ workSpecId,
+ removedInfo.getForegroundServiceType())
+ );
+ mCallback.cancelNotification(removedInfo.getNotificationId());
}
}
@@ -208,6 +219,8 @@
handleNotify(intent);
} else if (ACTION_CANCEL_WORK.equals(action)) {
handleCancelWork(intent);
+ } else if (ACTION_STOP_FOREGROUND.equals(action)) {
+ handleStop(intent);
}
}
@@ -289,14 +302,9 @@
}
@MainThread
- void handleStop() {
+ void handleStop(@NonNull Intent intent) {
Logger.get().info(TAG, "Stopping foreground service");
if (mCallback != null) {
- if (mLastForegroundInfo != null) {
- // Explicitly decrement the reference count for the notification.
- mCallback.cancelNotification(mLastForegroundInfo.getNotificationId());
- mLastForegroundInfo = null;
- }
mCallback.stop();
}
}
@@ -393,6 +401,19 @@
}
/**
+ * The {@link Intent} which can be used to stop {@link SystemForegroundService}.
+ *
+ * @param context The application {@link Context}
+ * @return The {@link Intent}
+ */
+ @NonNull
+ public static Intent createStopForegroundIntent(@NonNull Context context) {
+ Intent intent = new Intent(context, SystemForegroundService.class);
+ intent.setAction(ACTION_STOP_FOREGROUND);
+ return intent;
+ }
+
+ /**
* Used to notify that all pending commands are now completed.
*/
interface Callback {
diff --git a/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundService.java b/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundService.java
index 2c9c0f2..f893098 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundService.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundService.java
@@ -97,19 +97,6 @@
mDispatcher.setCallback(this);
}
- /**
- * Stops the foreground {@link Service} by asking {@link SystemForegroundDispatcher} to
- * handle a stop request.
- */
- public void stopForegroundService() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mDispatcher.handleStop();
- }
- });
- }
-
@MainThread
@Override
public void stop() {
diff --git a/work/workmanager/src/main/java/androidx/work/impl/utils/ProcessUtils.java b/work/workmanager/src/main/java/androidx/work/impl/utils/ProcessUtils.java
index d69e214..bab7665 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/utils/ProcessUtils.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/utils/ProcessUtils.java
@@ -24,6 +24,7 @@
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.os.Process;
import android.text.TextUtils;
@@ -57,10 +58,12 @@
@NonNull Configuration configuration) {
String processName = getProcessName(context);
+
if (!TextUtils.isEmpty(configuration.getDefaultProcessName())) {
return TextUtils.equals(processName, configuration.getDefaultProcessName());
} else {
- return TextUtils.equals(processName, context.getPackageName());
+ ApplicationInfo info = context.getApplicationInfo();
+ return TextUtils.equals(processName, info.processName);
}
}