blob: 81f5d38651cd0d54b14451a188d82fddfa0ae006 [file] [log] [blame]
Felipe Leme37f83722018-08-16 13:12:03 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.service.autofill;
18
19import static android.view.autofill.Helper.sDebug;
20import static android.view.autofill.Helper.sVerbose;
21
22import android.annotation.IdRes;
23import android.annotation.NonNull;
24import android.os.Parcel;
25import android.os.Parcelable;
26import android.util.Slog;
27import android.util.SparseIntArray;
28import android.view.View;
29import android.view.View.Visibility;
30import android.view.ViewGroup;
31import android.widget.RemoteViews;
32
33import com.android.internal.util.Preconditions;
34
35/**
36 * Action used to change the visibility of other child view in a {@link CustomDescription}
37 * {@link RemoteViews presentation template}.
38 *
39 * <p>See {@link CustomDescription.Builder#addOnClickAction(int, OnClickAction)} for more details.
40 */
41public final class VisibilitySetterAction extends InternalOnClickAction implements
42 OnClickAction, Parcelable {
43 private static final String TAG = "VisibilitySetterAction";
44
45 @NonNull private final SparseIntArray mVisibilities;
46
47 private VisibilitySetterAction(@NonNull Builder builder) {
48 mVisibilities = builder.mVisibilities;
49 }
50
51 /** @hide */
52 @Override
53 public void onClick(@NonNull ViewGroup rootView) {
54 for (int i = 0; i < mVisibilities.size(); i++) {
55 final int id = mVisibilities.keyAt(i);
56 final View child = rootView.findViewById(id);
57 if (child == null) {
58 Slog.w(TAG, "Skipping view id " + id + " because it's not found on " + rootView);
59 continue;
60 }
61 final int visibility = mVisibilities.valueAt(i);
62 if (sVerbose) {
63 Slog.v(TAG, "Changing visibility of view " + child + " from "
64 + child.getVisibility() + " to " + visibility);
65 }
66 child.setVisibility(visibility);
67 }
68 }
69
70 /**
71 * Builder for {@link VisibilitySetterAction} objects.
72 */
Felipe Lemece6877b2019-02-28 09:02:26 -080073 public static final class Builder {
Felipe Leme37f83722018-08-16 13:12:03 -070074 private final SparseIntArray mVisibilities = new SparseIntArray();
75 private boolean mDestroyed;
76
77 /**
78 * Creates a new builder for an action that change the visibility of one child view.
79 *
80 * @param id view resource id of the children view.
81 * @param visibility one of {@link View#VISIBLE}, {@link View#INVISIBLE}, or
82 * {@link View#GONE}.
Felipe Leme5d62f822018-08-21 11:34:13 -070083 * @throws IllegalArgumentException if visibility is not one of {@link View#VISIBLE},
Felipe Leme37f83722018-08-16 13:12:03 -070084 * {@link View#INVISIBLE}, or {@link View#GONE}.
85 */
86 public Builder(@IdRes int id, @Visibility int visibility) {
87 setVisibility(id, visibility);
88 }
89
90 /**
91 * Sets the action to changes the visibility of a child view.
92 *
93 * @param id view resource id of the children view.
94 * @param visibility one of {@link View#VISIBLE}, {@link View#INVISIBLE}, or
95 * {@link View#GONE}.
Felipe Leme5d62f822018-08-21 11:34:13 -070096 * @throws IllegalArgumentException if visibility is not one of {@link View#VISIBLE},
Felipe Leme37f83722018-08-16 13:12:03 -070097 * {@link View#INVISIBLE}, or {@link View#GONE}.
98 */
Felipe Lemece6877b2019-02-28 09:02:26 -080099 @NonNull
Felipe Leme37f83722018-08-16 13:12:03 -0700100 public Builder setVisibility(@IdRes int id, @Visibility int visibility) {
101 throwIfDestroyed();
102 switch (visibility) {
103 case View.VISIBLE:
104 case View.INVISIBLE:
105 case View.GONE:
106 mVisibilities.put(id, visibility);
107 return this;
108 }
109 throw new IllegalArgumentException("Invalid visibility: " + visibility);
110 }
111
112 /**
113 * Creates a new {@link VisibilitySetterAction} instance.
114 */
Felipe Lemece6877b2019-02-28 09:02:26 -0800115 @NonNull
Felipe Leme37f83722018-08-16 13:12:03 -0700116 public VisibilitySetterAction build() {
117 throwIfDestroyed();
118 mDestroyed = true;
119 return new VisibilitySetterAction(this);
120 }
121
122 private void throwIfDestroyed() {
123 Preconditions.checkState(!mDestroyed, "Already called build()");
124 }
125 }
126
127 /////////////////////////////////////
128 // Object "contract" methods. //
129 /////////////////////////////////////
130 @Override
131 public String toString() {
132 if (!sDebug) return super.toString();
133
134 return "VisibilitySetterAction: [" + mVisibilities + "]";
135 }
136
137 /////////////////////////////////////
138 // Parcelable "contract" methods. //
139 /////////////////////////////////////
140 @Override
141 public int describeContents() {
142 return 0;
143 }
144
145 @Override
146 public void writeToParcel(Parcel parcel, int flags) {
147 parcel.writeSparseIntArray(mVisibilities);
148 }
149
150 public static final Parcelable.Creator<VisibilitySetterAction> CREATOR =
151 new Parcelable.Creator<VisibilitySetterAction>() {
Felipe Lemece6877b2019-02-28 09:02:26 -0800152
153 @NonNull
Felipe Leme37f83722018-08-16 13:12:03 -0700154 @Override
155 public VisibilitySetterAction createFromParcel(Parcel parcel) {
156 // Always go through the builder to ensure the data ingested by
157 // the system obeys the contract of the builder to avoid attacks
158 final SparseIntArray visibilities = parcel.readSparseIntArray();
159 Builder builder = null;
160 for (int i = 0; i < visibilities.size(); i++) {
161 final int id = visibilities.keyAt(i);
162 final int visibility = visibilities.valueAt(i);
163 if (builder == null) {
164 builder = new Builder(id, visibility);
165 } else {
166 builder.setVisibility(id, visibility);
167 }
168 }
169 return builder == null ? null : builder.build();
170 }
171
Felipe Lemece6877b2019-02-28 09:02:26 -0800172 @NonNull
Felipe Leme37f83722018-08-16 13:12:03 -0700173 @Override
174 public VisibilitySetterAction[] newArray(int size) {
175 return new VisibilitySetterAction[size];
176 }
177 };
178}