ParceledListSlice.java revision 0e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3
10e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root/*
20e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * Copyright (C) 2011 The Android Open Source Project
30e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root *
40e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * Licensed under the Apache License, Version 2.0 (the "License");
50e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * you may not use this file except in compliance with the License.
60e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * You may obtain a copy of the License at
70e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root *
80e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root *      http://www.apache.org/licenses/LICENSE-2.0
90e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root *
100e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * Unless required by applicable law or agreed to in writing, software
110e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * distributed under the License is distributed on an "AS IS" BASIS,
120e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * See the License for the specific language governing permissions and
140e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * limitations under the License.
150e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root */
160e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
170e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Rootpackage android.content.pm;
180e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
190e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Rootimport android.os.Parcel;
200e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Rootimport android.os.Parcelable;
210e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
220e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Rootimport java.util.List;
230e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
240e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root/**
250e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * Builds up a parcel that is discarded when written to another parcel or
260e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * written to a list. This is useful for API that sends huge lists across a
270e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * Binder that may be larger than the IPC limit.
280e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root *
290e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * @hide
300e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root */
310e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Rootpublic class ParceledListSlice<T extends Parcelable> implements Parcelable {
320e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    /*
330e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * TODO get this number from somewhere else. For now set it to a quarter of
340e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * the 1MB limit.
350e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     */
360e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    private static final int MAX_IPC_SIZE = 256 * 1024;
370e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
380e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    private Parcel mParcel;
390e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
400e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    private int mNumItems;
410e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
420e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    private boolean mIsLastSlice;
430e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
440e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    public ParceledListSlice() {
450e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        mParcel = Parcel.obtain();
460e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    }
470e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
480e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    private ParceledListSlice(Parcel p, int numItems, boolean lastSlice) {
490e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        mParcel = p;
500e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        mNumItems = numItems;
510e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        mIsLastSlice = lastSlice;
520e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    }
530e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
540e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    @Override
550e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    public int describeContents() {
560e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        return 0;
570e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    }
580e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
590e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    /**
600e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * Write this to another Parcel. Note that this discards the internal Parcel
610e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * and should not be used anymore. This is so we can pass this to a Binder
620e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * where we won't have a chance to call recycle on this.
630e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     */
640e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    @Override
650e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    public void writeToParcel(Parcel dest, int flags) {
660e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        dest.writeInt(mNumItems);
670e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        dest.writeInt(mIsLastSlice ? 1 : 0);
680e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
690e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        if (mNumItems > 0) {
700e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            final int parcelSize = mParcel.dataSize();
710e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            dest.writeInt(parcelSize);
720e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            dest.appendFrom(mParcel, 0, parcelSize);
730e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        }
740e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
750e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        mNumItems = 0;
760e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        mParcel.recycle();
770e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        mParcel = null;
780e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    }
790e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
800e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    /**
810e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * Appends a parcel to this list slice.
820e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     *
830e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * @param item Parcelable item to append to this list slice
840e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * @return true when the list slice is full and should not be appended to
850e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     *         anymore
860e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     */
870e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    public boolean append(T item) {
880e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        if (mParcel == null) {
890e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            throw new IllegalStateException("ParceledListSlice has already been recycled");
900e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        }
910e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
920e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        item.writeToParcel(mParcel, PARCELABLE_WRITE_RETURN_VALUE);
930e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        mNumItems++;
940e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
950e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        return mParcel.dataSize() > MAX_IPC_SIZE;
960e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    }
970e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
980e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    /**
990e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * Populates a list and discards the internal state of the
1000e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * ParceledListSlice in the process. The instance should
1010e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * not be used anymore.
1020e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     *
1030e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * @param list list to insert items from this slice.
1040e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * @param creator creator that knows how to unparcel the
1050e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     *        target object type.
1060e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * @return the last item inserted into the list or null if none.
1070e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     */
1080e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    public T populateList(List<T> list, Creator<T> creator) {
1090e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        mParcel.setDataPosition(0);
1100e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1110e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        T item = null;
1120e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        for (int i = 0; i < mNumItems; i++) {
1130e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            item = creator.createFromParcel(mParcel);
1140e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            list.add(item);
1150e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        }
1160e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1170e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        mParcel.recycle();
1180e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        mParcel = null;
1190e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1200e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        return item;
1210e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    }
1220e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1230e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    /**
1240e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * Sets whether this is the last list slice in the series.
1250e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     *
1260e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * @param lastSlice
1270e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     */
1280e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    public void setLastSlice(boolean lastSlice) {
1290e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        mIsLastSlice = lastSlice;
1300e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    }
1310e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1320e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    /**
1330e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * Returns whether this is the last slice in a series of slices.
1340e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     *
1350e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * @return true if this is the last slice in the series.
1360e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     */
1370e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    public boolean isLastSlice() {
1380e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        return mIsLastSlice;
1390e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    }
1400e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1410e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    @SuppressWarnings("unchecked")
1420e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    public static final Parcelable.Creator<ParceledListSlice> CREATOR =
1430e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            new Parcelable.Creator<ParceledListSlice>() {
1440e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        public ParceledListSlice createFromParcel(Parcel in) {
1450e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            final int numItems = in.readInt();
1460e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            final boolean lastSlice = in.readInt() == 1;
1470e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1480e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            if (numItems > 0) {
1490e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root                final int parcelSize = in.readInt();
1500e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1510e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root                // Advance within this Parcel
1520e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root                int offset = in.dataPosition();
1530e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root                in.setDataPosition(offset + parcelSize);
1540e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1550e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root                Parcel p = Parcel.obtain();
1560e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root                p.setDataPosition(0);
1570e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root                p.appendFrom(in, offset, parcelSize);
1580e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root                p.setDataPosition(0);
1590e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1600e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root                return new ParceledListSlice(p, numItems, lastSlice);
1610e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            } else {
1620e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root                return new ParceledListSlice();
1630e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            }
1640e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        }
1650e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1660e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        public ParceledListSlice[] newArray(int size) {
1670e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            return new ParceledListSlice[size];
1680e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        }
1690e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    };
1700e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root}
171