1 /*
2  * Copyright 2020 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 
17 package androidx.recyclerview.widget;
18 
19 import androidx.collection.LongSparseArray;
20 
21 import org.jspecify.annotations.NonNull;
22 
23 /**
24  * Used by {@link ConcatAdapter} to isolate item ids between nested adapters, if necessary.
25  */
26 interface StableIdStorage {
createStableIdLookup()27     @NonNull StableIdLookup createStableIdLookup();
28 
29     /**
30      * Interface that provides {@link NestedAdapterWrapper}s a way to map their local stable ids
31      * into global stable ids, based on the configuration of the {@link ConcatAdapter}.
32      */
33     interface StableIdLookup {
localToGlobal(long localId)34         long localToGlobal(long localId);
35     }
36 
37     /**
38      * Returns {@link RecyclerView#NO_ID} for all positions. In other words, stable ids are not
39      * supported.
40      */
41     class NoStableIdStorage implements StableIdStorage {
42         private final StableIdLookup mNoIdLookup = new StableIdLookup() {
43             @Override
44             public long localToGlobal(long localId) {
45                 return RecyclerView.NO_ID;
46             }
47         };
48 
49         @Override
createStableIdLookup()50         public @NonNull StableIdLookup createStableIdLookup() {
51             return mNoIdLookup;
52         }
53     }
54 
55     /**
56      * A pass-through implementation that reports the stable id in sub adapters as is.
57      */
58     class SharedPoolStableIdStorage implements StableIdStorage {
59         private final StableIdLookup mSameIdLookup = new StableIdLookup() {
60             @Override
61             public long localToGlobal(long localId) {
62                 return localId;
63             }
64         };
65 
66         @Override
createStableIdLookup()67         public @NonNull StableIdLookup createStableIdLookup() {
68             return mSameIdLookup;
69         }
70     }
71 
72     /**
73      * An isolating implementation that ensures the stable ids among adapters do not conflict with
74      * each-other. It keeps a mapping for each adapter from its local stable ids to a global domain
75      * and always replaces the local id w/ a globally available ID to be consistent.
76      */
77     class IsolatedStableIdStorage implements StableIdStorage {
78         long mNextStableId = 0;
79 
obtainId()80         long obtainId() {
81             return mNextStableId++;
82         }
83 
84         @Override
createStableIdLookup()85         public @NonNull StableIdLookup createStableIdLookup() {
86             return new WrapperStableIdLookup();
87         }
88 
89         class WrapperStableIdLookup implements StableIdLookup {
90             private final LongSparseArray<Long> mLocalToGlobalLookup = new LongSparseArray<>();
91 
92             @Override
localToGlobal(long localId)93             public long localToGlobal(long localId) {
94                 Long globalId = mLocalToGlobalLookup.get(localId);
95                 if (globalId == null) {
96                     globalId = obtainId();
97                     mLocalToGlobalLookup.put(localId, globalId);
98                 }
99                 return globalId;
100             }
101         }
102     }
103 }
104