FileDocCategorySizeDatePackage
InputMethodSubtypeArray.javaAPI DocAndroid 5.1 API9759Thu Mar 12 22:22:10 GMT 2015android.view.inputmethod

InputMethodSubtypeArray

public class InputMethodSubtypeArray extends Object
An array-like container that stores multiple instances of {@link InputMethodSubtype}.

This container is designed to reduce the risk of {@link TransactionTooLargeException} when one or more instancess of {@link InputMethodInfo} are transferred through IPC. Basically this class does following three tasks.

  • Applying compression for the marshalled data
  • Lazily unmarshalling objects
  • Caching the marshalled data when appropriate
hide

Fields Summary
private static final String
TAG
private final Object
mLockObject
private final int
mCount
private volatile InputMethodSubtype[]
mInstance
private volatile byte[]
mCompressedData
private volatile int
mDecompressedSize
Constructors Summary
public InputMethodSubtypeArray(List subtypes)
Create a new instance of {@link InputMethodSubtypeArray} from an existing list of {@link InputMethodSubtype}.

param
subtypes A list of {@link InputMethodSubtype} from which {@link InputMethodSubtypeArray} will be created.


                                     
        
        if (subtypes == null) {
            mCount = 0;
            return;
        }
        mCount = subtypes.size();
        mInstance = subtypes.toArray(new InputMethodSubtype[mCount]);
    
public InputMethodSubtypeArray(android.os.Parcel source)
Unmarshall an instance of {@link InputMethodSubtypeArray} from a given {@link Parcel} object.

param
source A {@link Parcel} object from which {@link InputMethodSubtypeArray} will be unmarshalled.

        mCount = source.readInt();
        if (mCount > 0) {
            mDecompressedSize = source.readInt();
            mCompressedData = source.createByteArray();
        }
    
Methods Summary
private static byte[]compress(byte[] data)

        ByteArrayOutputStream resultStream = null;
        GZIPOutputStream zipper = null;
        try {
            resultStream = new ByteArrayOutputStream();
            zipper = new GZIPOutputStream(resultStream);
            zipper.write(data);
        } catch(IOException e) {
            return null;
        } finally {
            try {
                if (zipper != null) {
                    zipper.close();
                }
            } catch (IOException e) {
                zipper = null;
                Slog.e(TAG, "Failed to close the stream.", e);
                // swallowed, not propagated back to the caller
            }
            try {
                if (resultStream != null) {
                    resultStream.close();
                }
            } catch (IOException e) {
                resultStream = null;
                Slog.e(TAG, "Failed to close the stream.", e);
                // swallowed, not propagated back to the caller
            }
        }
        return resultStream != null ? resultStream.toByteArray() : null;
    
private static byte[]decompress(byte[] data, int expectedSize)

        ByteArrayInputStream inputStream = null;
        GZIPInputStream unzipper = null;
        try {
            inputStream = new ByteArrayInputStream(data);
            unzipper = new GZIPInputStream(inputStream);
            final byte [] result = new byte[expectedSize];
            int totalReadBytes = 0;
            while (totalReadBytes < result.length) {
                final int restBytes = result.length - totalReadBytes;
                final int readBytes = unzipper.read(result, totalReadBytes, restBytes);
                if (readBytes < 0) {
                    break;
                }
                totalReadBytes += readBytes;
            }
            if (expectedSize != totalReadBytes) {
                return null;
            }
            return result;
        } catch(IOException e) {
            return null;
        } finally {
            try {
                if (unzipper != null) {
                    unzipper.close();
                }
            } catch (IOException e) {
                Slog.e(TAG, "Failed to close the stream.", e);
                // swallowed, not propagated back to the caller
            }
            try {
                if (inputStream != null) {
                  inputStream.close();
                }
            } catch (IOException e) {
                Slog.e(TAG, "Failed to close the stream.", e);
                // swallowed, not propagated back to the caller
            }
        }
    
public InputMethodSubtypeget(int index)
Return {@link InputMethodSubtype} specified with the given index.

This methods may take a bit additional time to decompress data lazily when called first time.

param
index The index of {@link InputMethodSubtype}.

        if (index < 0 || mCount <= index) {
            throw new ArrayIndexOutOfBoundsException();
        }
        InputMethodSubtype[] instance = mInstance;
        if (instance == null) {
            synchronized (mLockObject) {
                instance = mInstance;
                if (instance == null) {
                    final byte[] decompressedData =
                          decompress(mCompressedData, mDecompressedSize);
                    // Clear the compressed data until {@link #getMarshalled()} is called.
                    mCompressedData = null;
                    mDecompressedSize = 0;
                    if (decompressedData != null) {
                        instance = unmarshall(decompressedData);
                    } else {
                        Slog.e(TAG, "Failed to decompress data. Returns null as fallback.");
                        instance = new InputMethodSubtype[mCount];
                    }
                    mInstance = instance;
                }
            }
        }
        return instance[index];
    
public intgetCount()
Return the number of {@link InputMethodSubtype} objects.

        return mCount;
    
private static byte[]marshall(InputMethodSubtype[] array)


          
        Parcel parcel = null;
        try {
            parcel = Parcel.obtain();
            parcel.writeTypedArray(array, 0);
            return parcel.marshall();
        } finally {
            if (parcel != null) {
                parcel.recycle();
                parcel = null;
            }
        }
    
private static InputMethodSubtype[]unmarshall(byte[] data)

        Parcel parcel = null;
        try {
            parcel = Parcel.obtain();
            parcel.unmarshall(data, 0, data.length);
            parcel.setDataPosition(0);
            return parcel.createTypedArray(InputMethodSubtype.CREATOR);
        } finally {
            if (parcel != null) {
                parcel.recycle();
                parcel = null;
            }
        }
    
public voidwriteToParcel(android.os.Parcel dest)
Marshall the instance into a given {@link Parcel} object.

This methods may take a bit additional time to compress data lazily when called first time.

param
source A {@link Parcel} object to which {@link InputMethodSubtypeArray} will be marshalled.

        if (mCount == 0) {
            dest.writeInt(mCount);
            return;
        }

        byte[] compressedData = mCompressedData;
        int decompressedSize = mDecompressedSize;
        if (compressedData == null && decompressedSize == 0) {
            synchronized (mLockObject) {
                compressedData = mCompressedData;
                decompressedSize = mDecompressedSize;
                if (compressedData == null && decompressedSize == 0) {
                    final byte[] decompressedData = marshall(mInstance);
                    compressedData = compress(decompressedData);
                    if (compressedData == null) {
                        decompressedSize = -1;
                        Slog.i(TAG, "Failed to compress data.");
                    } else {
                        decompressedSize = decompressedData.length;
                    }
                    mDecompressedSize = decompressedSize;
                    mCompressedData = compressedData;
                }
            }
        }

        if (compressedData != null && decompressedSize > 0) {
            dest.writeInt(mCount);
            dest.writeInt(decompressedSize);
            dest.writeByteArray(compressedData);
        } else {
            Slog.i(TAG, "Unexpected state. Behaving as an empty array.");
            dest.writeInt(0);
        }