[go: nahoru, domu]

blob: a27752f1591ade44d7bc5b46d1ddb6d231d42a7d [file] [log] [blame]
Steve McKay7fb76352017-11-17 11:21:15 -08001/*
2 * Copyright 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
Aurimas Liutikas2a32c7e2018-03-02 11:19:14 -080017package androidx.recyclerview.selection;
Steve McKay7fb76352017-11-17 11:21:15 -080018
Aurimas Liutikasac5fe7c2018-03-06 14:40:53 -080019import static androidx.core.util.Preconditions.checkArgument;
Steve McKay7fb76352017-11-17 11:21:15 -080020
21import android.os.Bundle;
22import android.os.Parcelable;
Aurimas Liutikas60dadae2018-03-13 14:12:58 -070023
Aurimas Liutikasac5fe7c2018-03-06 14:40:53 -080024import androidx.annotation.NonNull;
25import androidx.annotation.Nullable;
26import androidx.annotation.VisibleForTesting;
Steve McKay7fb76352017-11-17 11:21:15 -080027
28import java.util.ArrayList;
29
30/**
31 * Strategy for storing keys in saved state. Extend this class when using custom
Steve McKay83f74642018-01-26 15:18:55 -080032 * key types that aren't supported by default. Prefer use of builtin storage strategies:
Steve McKay7fb76352017-11-17 11:21:15 -080033 * {@link #createStringStorage()}, {@link #createLongStorage()},
34 * {@link #createParcelableStorage(Class)}.
35 *
Steve McKay83f74642018-01-26 15:18:55 -080036 * <p>
37 * See
Aurimas Liutikas2a32c7e2018-03-02 11:19:14 -080038 * {@link androidx.recyclerview.selection.SelectionTracker.Builder SelectionTracker.Builder}
Steve McKay83f74642018-01-26 15:18:55 -080039 * for more detailed advice on which key type to use for your selection keys.
Steve McKay7fb76352017-11-17 11:21:15 -080040 *
41 * @param <K> Selection key type. Built in support is provided for String, Long, and Parcelable
42 * types. Use the respective factory method to create a StorageStrategy instance
43 * appropriate to the desired type.
44 * {@link #createStringStorage()},
45 * {@link #createParcelableStorage(Class)},
46 * {@link #createLongStorage()}
47 */
48public abstract class StorageStrategy<K> {
49
50 @VisibleForTesting
Aurimas Liutikas2a32c7e2018-03-02 11:19:14 -080051 static final String SELECTION_ENTRIES = "androidx.recyclerview.selection.entries";
Steve McKay7fb76352017-11-17 11:21:15 -080052
53 @VisibleForTesting
Aurimas Liutikas2a32c7e2018-03-02 11:19:14 -080054 static final String SELECTION_KEY_TYPE = "androidx.recyclerview.selection.type";
Steve McKay7fb76352017-11-17 11:21:15 -080055
56 private final Class<K> mType;
57
58 /**
59 * Creates a new instance.
60 *
61 * @param type the key type class that is being used.
62 */
63 public StorageStrategy(@NonNull Class<K> type) {
64 checkArgument(type != null);
65 mType = type;
66 }
67
68 /**
69 * Create a {@link Selection} from supplied {@link Bundle}.
70 *
71 * @param state Bundle instance that may contain parceled Selection instance.
72 * @return
73 */
74 public abstract @Nullable Selection<K> asSelection(@NonNull Bundle state);
75
76 /**
77 * Creates a {@link Bundle} from supplied {@link Selection}.
78 *
79 * @param selection The selection to asBundle.
80 * @return
81 */
82 public abstract @NonNull Bundle asBundle(@NonNull Selection<K> selection);
83
84 String getKeyTypeName() {
85 return mType.getCanonicalName();
86 }
87
88 /**
89 * @return StorageStrategy suitable for use with {@link Parcelable} keys
90 * (like {@link android.net.Uri}).
91 */
92 public static <K extends Parcelable> StorageStrategy<K> createParcelableStorage(Class<K> type) {
93 return new ParcelableStorageStrategy(type);
94 }
95
96 /**
97 * @return StorageStrategy suitable for use with {@link String} keys.
98 */
99 public static StorageStrategy<String> createStringStorage() {
100 return new StringStorageStrategy();
101 }
102
103 /**
104 * @return StorageStrategy suitable for use with {@link Long} keys.
105 */
106 public static StorageStrategy<Long> createLongStorage() {
107 return new LongStorageStrategy();
108 }
109
110 private static class StringStorageStrategy extends StorageStrategy<String> {
111
112 StringStorageStrategy() {
113 super(String.class);
114 }
115
116 @Override
117 public @Nullable Selection<String> asSelection(@NonNull Bundle state) {
118
119 String keyType = state.getString(SELECTION_KEY_TYPE, null);
120 if (keyType == null || !keyType.equals(getKeyTypeName())) {
121 return null;
122 }
123
124 @Nullable ArrayList<String> stored = state.getStringArrayList(SELECTION_ENTRIES);
125 if (stored == null) {
126 return null;
127 }
128
129 Selection<String> selection = new Selection<>();
130 selection.mSelection.addAll(stored);
131 return selection;
132 }
133
134 @Override
135 public @NonNull Bundle asBundle(@NonNull Selection<String> selection) {
136
137 Bundle bundle = new Bundle();
138
139 bundle.putString(SELECTION_KEY_TYPE, getKeyTypeName());
140
141 ArrayList<String> value = new ArrayList<>(selection.size());
142 value.addAll(selection.mSelection);
143 bundle.putStringArrayList(SELECTION_ENTRIES, value);
144
145 return bundle;
146 }
147 }
148
149 private static class LongStorageStrategy extends StorageStrategy<Long> {
150
151 LongStorageStrategy() {
152 super(Long.class);
153 }
154
155 @Override
156 public @Nullable Selection<Long> asSelection(@NonNull Bundle state) {
157 String keyType = state.getString(SELECTION_KEY_TYPE, null);
158 if (keyType == null || !keyType.equals(getKeyTypeName())) {
159 return null;
160 }
161
162 @Nullable long[] stored = state.getLongArray(SELECTION_ENTRIES);
163 if (stored == null) {
164 return null;
165 }
166
167 Selection<Long> selection = new Selection<>();
168 for (long key : stored) {
169 selection.mSelection.add(key);
170 }
171 return selection;
172 }
173
174 @Override
175 public @NonNull Bundle asBundle(@NonNull Selection<Long> selection) {
176
177 Bundle bundle = new Bundle();
178 bundle.putString(SELECTION_KEY_TYPE, getKeyTypeName());
179
180 long[] value = new long[selection.size()];
181 int i = 0;
182 for (Long key : selection) {
183 value[i++] = key;
184 }
185 bundle.putLongArray(SELECTION_ENTRIES, value);
186
187 return bundle;
188 }
189 }
190
191 private static class ParcelableStorageStrategy<K extends Parcelable>
192 extends StorageStrategy<K> {
193
194 ParcelableStorageStrategy(Class<K> type) {
195 super(type);
196 checkArgument(Parcelable.class.isAssignableFrom(type));
197 }
198
199 @Override
200 public @Nullable Selection<K> asSelection(@NonNull Bundle state) {
201
202 String keyType = state.getString(SELECTION_KEY_TYPE, null);
203 if (keyType == null || !keyType.equals(getKeyTypeName())) {
204 return null;
205 }
206
207 @Nullable ArrayList<K> stored = state.getParcelableArrayList(SELECTION_ENTRIES);
208 if (stored == null) {
209 return null;
210 }
211
212 Selection<K> selection = new Selection<>();
213 selection.mSelection.addAll(stored);
214 return selection;
215 }
216
217 @Override
218 public @NonNull Bundle asBundle(@NonNull Selection<K> selection) {
219
220 Bundle bundle = new Bundle();
221 bundle.putString(SELECTION_KEY_TYPE, getKeyTypeName());
222
223 ArrayList<K> value = new ArrayList<>(selection.size());
224 value.addAll(selection.mSelection);
225 bundle.putParcelableArrayList(SELECTION_ENTRIES, value);
226
227 return bundle;
228 }
229 }
230}