• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 android.content.pm;
18 
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 
22 import java.util.List;
23 
24 /**
25  * Builds up a parcel that is discarded when written to another parcel or
26  * written to a list. This is useful for API that sends huge lists across a
27  * Binder that may be larger than the IPC limit.
28  *
29  * @hide
30  */
31 public class ParceledListSlice<T extends Parcelable> implements Parcelable {
32     /*
33      * TODO get this number from somewhere else. For now set it to a quarter of
34      * the 1MB limit.
35      */
36     private static final int MAX_IPC_SIZE = 256 * 1024;
37 
38     private Parcel mParcel;
39 
40     private int mNumItems;
41 
42     private boolean mIsLastSlice;
43 
ParceledListSlice()44     public ParceledListSlice() {
45         mParcel = Parcel.obtain();
46     }
47 
ParceledListSlice(Parcel p, int numItems, boolean lastSlice)48     private ParceledListSlice(Parcel p, int numItems, boolean lastSlice) {
49         mParcel = p;
50         mNumItems = numItems;
51         mIsLastSlice = lastSlice;
52     }
53 
54     @Override
describeContents()55     public int describeContents() {
56         return 0;
57     }
58 
59     /**
60      * Write this to another Parcel. Note that this discards the internal Parcel
61      * and should not be used anymore. This is so we can pass this to a Binder
62      * where we won't have a chance to call recycle on this.
63      */
64     @Override
writeToParcel(Parcel dest, int flags)65     public void writeToParcel(Parcel dest, int flags) {
66         dest.writeInt(mNumItems);
67         dest.writeInt(mIsLastSlice ? 1 : 0);
68 
69         if (mNumItems > 0) {
70             final int parcelSize = mParcel.dataSize();
71             dest.writeInt(parcelSize);
72             dest.appendFrom(mParcel, 0, parcelSize);
73         }
74 
75         mNumItems = 0;
76         mParcel.recycle();
77         mParcel = null;
78     }
79 
80     /**
81      * Appends a parcel to this list slice.
82      *
83      * @param item Parcelable item to append to this list slice
84      * @return true when the list slice is full and should not be appended to
85      *         anymore
86      */
append(T item)87     public boolean append(T item) {
88         if (mParcel == null) {
89             throw new IllegalStateException("ParceledListSlice has already been recycled");
90         }
91 
92         item.writeToParcel(mParcel, PARCELABLE_WRITE_RETURN_VALUE);
93         mNumItems++;
94 
95         return mParcel.dataSize() > MAX_IPC_SIZE;
96     }
97 
98     /**
99      * Populates a list and discards the internal state of the
100      * ParceledListSlice in the process. The instance should
101      * not be used anymore.
102      *
103      * @param list list to insert items from this slice.
104      * @param creator creator that knows how to unparcel the
105      *        target object type.
106      * @return the last item inserted into the list or null if none.
107      */
populateList(List<T> list, Creator<T> creator)108     public T populateList(List<T> list, Creator<T> creator) {
109         mParcel.setDataPosition(0);
110 
111         T item = null;
112         for (int i = 0; i < mNumItems; i++) {
113             item = creator.createFromParcel(mParcel);
114             list.add(item);
115         }
116 
117         mParcel.recycle();
118         mParcel = null;
119 
120         return item;
121     }
122 
123     /**
124      * Sets whether this is the last list slice in the series.
125      *
126      * @param lastSlice
127      */
setLastSlice(boolean lastSlice)128     public void setLastSlice(boolean lastSlice) {
129         mIsLastSlice = lastSlice;
130     }
131 
132     /**
133      * Returns whether this is the last slice in a series of slices.
134      *
135      * @return true if this is the last slice in the series.
136      */
isLastSlice()137     public boolean isLastSlice() {
138         return mIsLastSlice;
139     }
140 
141     @SuppressWarnings("unchecked")
142     public static final Parcelable.Creator<ParceledListSlice> CREATOR =
143             new Parcelable.Creator<ParceledListSlice>() {
144         public ParceledListSlice createFromParcel(Parcel in) {
145             final int numItems = in.readInt();
146             final boolean lastSlice = in.readInt() == 1;
147 
148             if (numItems > 0) {
149                 final int parcelSize = in.readInt();
150 
151                 // Advance within this Parcel
152                 int offset = in.dataPosition();
153                 in.setDataPosition(offset + parcelSize);
154 
155                 Parcel p = Parcel.obtain();
156                 p.setDataPosition(0);
157                 p.appendFrom(in, offset, parcelSize);
158                 p.setDataPosition(0);
159 
160                 return new ParceledListSlice(p, numItems, lastSlice);
161             } else {
162                 return new ParceledListSlice();
163             }
164         }
165 
166         public ParceledListSlice[] newArray(int size) {
167             return new ParceledListSlice[size];
168         }
169     };
170 }
171