content: package com.lody.virtual.remote;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import android.os.Binder;
  import android.os.IBinder;
  import android.os.Parcel;
  import android.os.Parcelable;
  import android.os.RemoteException;
  import android.util.Log;
  
  /**
   * Transfer a large list of Parcelable objects across an IPC. Splits into
   * multiple transactions if needed.
   *
   * Caveat: for efficiency and security, all elements must be the same concrete
   * type. In order to avoid writing the class name of each object, we must ensure
   * that each object is the same type, or else unparceling then reparceling the
   * data may yield a different result if the class name encoded in the Parcelable
   * is a Base type. See b/17671747.
   *
   * @hide
   *
   * 		OpenSilk: Modified to remove the creator optimization which uses hidden
   *       apis. this means we write an extra string for every list item. Class
   *       verification left in place since the Base type issue still applies
   */
  public class VParceledListSlice<T extends Parcelable> implements Parcelable {
  	@SuppressWarnings("unchecked")
  	public static final Parcelable.ClassLoaderCreator<VParceledListSlice> CREATOR = new Parcelable.ClassLoaderCreator<VParceledListSlice>() {
  		public VParceledListSlice createFromParcel(Parcel in) {
  			return new VParceledListSlice(in, null);
  		}
  
  		@Override
  		public VParceledListSlice createFromParcel(Parcel in, ClassLoader loader) {
  			return new VParceledListSlice(in, loader);
  		}
  
  		public VParceledListSlice[] newArray(int size) {
  			return new VParceledListSlice[size];
  		}
  	};
  	/*
  	 * TODO get this number from somewhere else. For now set it to a quarter of
  	 * the 1MB limit.
  	 */
  	private static final int MAX_IPC_SIZE = 256 * 1024;
  	private static final int MAX_FIRST_IPC_SIZE = MAX_IPC_SIZE / 2;
  	private static String TAG = "ParceledListSlice";
  	private static boolean DEBUG = false;
  	private final List<T> mList;
  
  	public VParceledListSlice(List<T> list) {
  		mList = list;
  	}
  
  	private VParceledListSlice(Parcel p, ClassLoader loader) {
  		final int N = p.readInt();
  		mList = new ArrayList<T>(N);
  		if (DEBUG)
  			Log.d(TAG, "Retrieving " + N + " items");
  		if (N <= 0) {
  			return;
  		}
  
  		// Parcelable.Creator<T> creator = p.readParcelableCreator(loader);
  		Class<?> listElementClass = null;
  
  		int i = 0;
  		while (i < N) {
  			if (p.readInt() == 0) {
  				break;
  			}
  
  			// final T parcelable = p.readCreator(creator, loader);
  			final T parcelable = p.readParcelable(loader);
  			if (listElementClass == null) {
  				listElementClass = parcelable.getClass();
  			} else {
  				verifySameType(listElementClass, parcelable.getClass());
  			}
  
  			mList.add(parcelable);
  
  			if (DEBUG)
  				Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size() - 1));
  			i++;
  		}
  		if (i >= N) {
  			return;
  		}
  		final IBinder retriever = p.readStrongBinder();
  		while (i < N) {
  			if (DEBUG)
  				Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever);
  			Parcel data = Parcel.obtain();
  			Parcel reply = Parcel.obtain();
  			data.writeInt(i);
  			try {
  				retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
  			} catch (RemoteException e) {
  				Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
  				return;
  			}
  			while (i < N && reply.readInt() != 0) {
  				// final T parcelable = reply.readCreator(creator, loader);
  				final T parcelable = reply.readParcelable(loader);
  				verifySameType(listElementClass, parcelable.getClass());
  
  				mList.add(parcelable);
  
  				if (DEBUG)
  					Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size() - 1));
  				i++;
  			}
  			reply.recycle();
  			data.recycle();
  		}
  	}
  
  	private static void verifySameType(final Class<?> expected, final Class<?> actual) {
  		if (!actual.equals(expected)) {
  			throw new IllegalArgumentException(
  					"Can't unparcel type " + actual.getName() + " in list of type " + expected.getName());
  		}
  	}
  
  	public List<T> getList() {
  		return mList;
  	}
  
  	@Override
  	public int describeContents() {
  		int contents = 0;
  		for (int i = 0; i < mList.size(); i++) {
  			contents |= mList.get(i).describeContents();
  		}
  		return contents;
  	}
  
  	/**
  	 * Write this to another Parcel. Note that this discards the internal Parcel
  	 * and should not be used anymore. This is so we can pass this to a Binder
  	 * where we won't have a chance to call recycle on this.
  	 */
  	@Override
  	public void writeToParcel(Parcel dest, int flags) {
  		final int N = mList.size();
  		final int callFlags = flags;
  		dest.writeInt(N);
  		if (DEBUG)
  			Log.d(TAG, "Writing " + N + " items");
  		if (N > 0) {
  			final Class<?> listElementClass = mList.get(0).getClass();
  			// dest.writeParcelableCreator(mList.get(0));
  			int i = 0;
  			while (i < N && dest.dataSize() < MAX_FIRST_IPC_SIZE) {
  				dest.writeInt(1);
  
  				final T parcelable = mList.get(i);
  				verifySameType(listElementClass, parcelable.getClass());
  				// parcelable.writeToParcel(dest, callFlags);
  				dest.writeParcelable(parcelable, callFlags);
  
  				if (DEBUG)
  					Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
  				i++;
  			}
  			if (i < N) {
  				dest.writeInt(0);
  				Binder retriever = new Binder() {
  					@Override
  					protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
  							throws RemoteException {
  						if (code != FIRST_CALL_TRANSACTION) {
  							return super.onTransact(code, data, reply, flags);
  						}
  						int i = data.readInt();
  						if (DEBUG)
  							Log.d(TAG, "Writing more @" + i + " of " + N);
  						while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
  							reply.writeInt(1);
  
  							final T parcelable = mList.get(i);
  							verifySameType(listElementClass, parcelable.getClass());
  							// parcelable.writeToParcel(reply, callFlags);
  							reply.writeParcelable(parcelable, callFlags);
  
  							if (DEBUG)
  								Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
  							i++;
  						}
  						if (i < N) {
  							if (DEBUG)
  								Log.d(TAG, "Breaking @" + i + " of " + N);
  							reply.writeInt(0);
  						}
  						return true;
  					}
  				};
  				if (DEBUG)
  					Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever);
  				dest.writeStrongBinder(retriever);
  			}
  		}
  	}
  }