221 lines
8.0 KiB
Java
221 lines
8.0 KiB
Java
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.service.autofill;
|
|
|
|
import static android.view.autofill.Helper.sDebug;
|
|
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
import android.util.Pair;
|
|
import android.widget.RemoteViews;
|
|
|
|
import com.android.internal.util.Preconditions;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Objects;
|
|
|
|
/**
|
|
* Defines actions to be applied to a {@link RemoteViews template presentation}.
|
|
*
|
|
*
|
|
* <p>It supports 2 types of actions:
|
|
*
|
|
* <ol>
|
|
* <li>{@link RemoteViews Actions} to be applied to the template.
|
|
* <li>{@link Transformation Transformations} to be applied on child views.
|
|
* </ol>
|
|
*
|
|
* <p>Typically used on {@link CustomDescription custom descriptions} to conditionally display
|
|
* differents views based on user input - see
|
|
* {@link CustomDescription.Builder#batchUpdate(Validator, BatchUpdates)} for more information.
|
|
*/
|
|
public final class BatchUpdates implements Parcelable {
|
|
|
|
private final ArrayList<Pair<Integer, InternalTransformation>> mTransformations;
|
|
private final RemoteViews mUpdates;
|
|
|
|
private BatchUpdates(Builder builder) {
|
|
mTransformations = builder.mTransformations;
|
|
mUpdates = builder.mUpdates;
|
|
}
|
|
|
|
/** @hide */
|
|
@Nullable
|
|
public ArrayList<Pair<Integer, InternalTransformation>> getTransformations() {
|
|
return mTransformations;
|
|
}
|
|
|
|
/** @hide */
|
|
@Nullable
|
|
public RemoteViews getUpdates() {
|
|
return mUpdates;
|
|
}
|
|
|
|
/**
|
|
* Builder for {@link BatchUpdates} objects.
|
|
*/
|
|
public static class Builder {
|
|
private RemoteViews mUpdates;
|
|
|
|
private boolean mDestroyed;
|
|
private ArrayList<Pair<Integer, InternalTransformation>> mTransformations;
|
|
|
|
/**
|
|
* Applies the {@code updates} in the underlying presentation template.
|
|
*
|
|
* <p><b>Note:</b> The updates are applied before the
|
|
* {@link #transformChild(int, Transformation) transformations} are applied to the children
|
|
* views.
|
|
*
|
|
* <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color
|
|
* or background color: Autofill on different platforms may have different themes.
|
|
*
|
|
* @param updates a {@link RemoteViews} with the updated actions to be applied in the
|
|
* underlying presentation template.
|
|
*
|
|
* @return this builder
|
|
* @throws IllegalArgumentException if {@code condition} is not a class provided
|
|
* by the Android System.
|
|
*/
|
|
public Builder updateTemplate(@NonNull RemoteViews updates) {
|
|
throwIfDestroyed();
|
|
mUpdates = Objects.requireNonNull(updates);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds a transformation to replace the value of a child view with the fields in the
|
|
* screen.
|
|
*
|
|
* <p>When multiple transformations are added for the same child view, they are applied
|
|
* in the same order as added.
|
|
*
|
|
* <p><b>Note:</b> The transformations are applied after the
|
|
* {@link #updateTemplate(RemoteViews) updates} are applied to the presentation template.
|
|
*
|
|
* @param id view id of the children view.
|
|
* @param transformation an implementation provided by the Android System.
|
|
* @return this builder.
|
|
* @throws IllegalArgumentException if {@code transformation} is not a class provided
|
|
* by the Android System.
|
|
*/
|
|
public Builder transformChild(int id, @NonNull Transformation transformation) {
|
|
throwIfDestroyed();
|
|
Preconditions.checkArgument((transformation instanceof InternalTransformation),
|
|
"not provided by Android System: %s", transformation);
|
|
if (mTransformations == null) {
|
|
mTransformations = new ArrayList<>();
|
|
}
|
|
mTransformations.add(new Pair<>(id, (InternalTransformation) transformation));
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Creates a new {@link BatchUpdates} instance.
|
|
*
|
|
* @throws IllegalStateException if {@link #build()} was already called before or no call
|
|
* to {@link #updateTemplate(RemoteViews)} or {@link #transformChild(int, Transformation)}
|
|
* has been made.
|
|
*/
|
|
public BatchUpdates build() {
|
|
throwIfDestroyed();
|
|
Preconditions.checkState(mUpdates != null || mTransformations != null,
|
|
"must call either updateTemplate() or transformChild() at least once");
|
|
mDestroyed = true;
|
|
return new BatchUpdates(this);
|
|
}
|
|
|
|
private void throwIfDestroyed() {
|
|
if (mDestroyed) {
|
|
throw new IllegalStateException("Already called #build()");
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
// Object "contract" methods. //
|
|
/////////////////////////////////////
|
|
@Override
|
|
public String toString() {
|
|
if (!sDebug) return super.toString();
|
|
|
|
return new StringBuilder("BatchUpdates: [")
|
|
.append(", transformations=")
|
|
.append(mTransformations == null ? "N/A" : mTransformations.size())
|
|
.append(", updates=").append(mUpdates)
|
|
.append("]").toString();
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
// Parcelable "contract" methods. //
|
|
/////////////////////////////////////
|
|
@Override
|
|
public int describeContents() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public void writeToParcel(Parcel dest, int flags) {
|
|
if (mTransformations == null) {
|
|
dest.writeIntArray(null);
|
|
} else {
|
|
final int size = mTransformations.size();
|
|
final int[] ids = new int[size];
|
|
final InternalTransformation[] values = new InternalTransformation[size];
|
|
for (int i = 0; i < size; i++) {
|
|
final Pair<Integer, InternalTransformation> pair = mTransformations.get(i);
|
|
ids[i] = pair.first;
|
|
values[i] = pair.second;
|
|
}
|
|
dest.writeIntArray(ids);
|
|
dest.writeParcelableArray(values, flags);
|
|
}
|
|
dest.writeParcelable(mUpdates, flags);
|
|
}
|
|
public static final @android.annotation.NonNull Parcelable.Creator<BatchUpdates> CREATOR =
|
|
new Parcelable.Creator<BatchUpdates>() {
|
|
@Override
|
|
public BatchUpdates createFromParcel(Parcel parcel) {
|
|
// Always go through the builder to ensure the data ingested by
|
|
// the system obeys the contract of the builder to avoid attacks
|
|
// using specially crafted parcels.
|
|
final Builder builder = new Builder();
|
|
final int[] ids = parcel.createIntArray();
|
|
if (ids != null) {
|
|
final InternalTransformation[] values =
|
|
parcel.readParcelableArray(null, InternalTransformation.class);
|
|
final int size = ids.length;
|
|
for (int i = 0; i < size; i++) {
|
|
builder.transformChild(ids[i], values[i]);
|
|
}
|
|
}
|
|
final RemoteViews updates = parcel.readParcelable(null, android.widget.RemoteViews.class);
|
|
if (updates != null) {
|
|
builder.updateTemplate(updates);
|
|
}
|
|
return builder.build();
|
|
}
|
|
|
|
@Override
|
|
public BatchUpdates[] newArray(int size) {
|
|
return new BatchUpdates[size];
|
|
}
|
|
};
|
|
}
|