InputMethodSubtypeArray.java revision f06569561fe1c6e898debf8bb9f37331a9f87323
1f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa/* 2f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * Copyright (C) 2007-2014 The Android Open Source Project 3f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * 4f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * use this file except in compliance with the License. You may obtain a copy of 6f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * the License at 7f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * 8f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * http://www.apache.org/licenses/LICENSE-2.0 9f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * 10f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * Unless required by applicable law or agreed to in writing, software 11f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * License for the specific language governing permissions and limitations under 14f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * the License. 15f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa */ 16f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 17f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawapackage android.view.inputmethod; 18f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 19f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport android.os.Parcel; 20f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport android.os.Parcelable; 21f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport android.util.AndroidRuntimeException; 22f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport android.util.Slog; 23f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 24f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.io.ByteArrayInputStream; 25f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.io.ByteArrayOutputStream; 26f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.io.IOException; 27f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.io.InputStream; 28f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.io.OutputStream; 29f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.util.List; 30f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.util.zip.GZIPInputStream; 31f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.util.zip.GZIPOutputStream; 32f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 33f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa/** 34f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * An array-like container that stores multiple instances of {@link InputMethodSubtype}. 35f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * 36f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * <p>This container is designed to reduce the risk of {@link TransactionTooLargeException} 37f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * when one or more instancess of {@link InputMethodInfo} are transferred through IPC. 38f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * Basically this class does following three tasks.</p> 39f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * <ul> 40f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * <li>Applying compression for the marshalled data</li> 41f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * <li>Lazily unmarshalling objects</li> 42f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * <li>Caching the marshalled data when appropriate</li> 43f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * </ul> 44f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * 45f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * @hide 46f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa */ 47f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawapublic class InputMethodSubtypeArray { 48f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa private final static String TAG = "InputMethodSubtypeArray"; 49f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 50f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa /** 51f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * Create a new instance of {@link InputMethodSubtypeArray} from an existing list of 52f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * {@link InputMethodSubtype}. 53f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * 54f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * @param subtypes A list of {@link InputMethodSubtype} from which 55f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * {@link InputMethodSubtypeArray} will be created. 56f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa */ 57f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa public InputMethodSubtypeArray(final List<InputMethodSubtype> subtypes) { 58f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (subtypes == null) { 59f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa mCount = 0; 60f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa return; 61f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 62f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa mCount = subtypes.size(); 63f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa mInstance = subtypes.toArray(new InputMethodSubtype[mCount]); 64f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 65f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 66f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa /** 67f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * Unmarshall an instance of {@link InputMethodSubtypeArray} from a given {@link Parcel} 68f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * object. 69f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * 70f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * @param source A {@link Parcel} object from which {@link InputMethodSubtypeArray} will be 71f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * unmarshalled. 72f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa */ 73f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa public InputMethodSubtypeArray(final Parcel source) { 74f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa mCount = source.readInt(); 75f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (mCount > 0) { 76f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa mDecompressedSize = source.readInt(); 77f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa mCompressedData = source.createByteArray(); 78f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 79f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 80f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 81f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa /** 82f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * Marshall the instance into a given {@link Parcel} object. 83f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * 84f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * <p>This methods may take a bit additional time to compress data lazily when called 85f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * first time.</p> 86f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * 87f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * @param source A {@link Parcel} object to which {@link InputMethodSubtypeArray} will be 88f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * marshalled. 89f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa */ 90f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa public void writeToParcel(final Parcel dest) { 91f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (mCount == 0) { 92f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa dest.writeInt(mCount); 93f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa return; 94f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 95f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 96f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa byte[] compressedData = mCompressedData; 97f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa int decompressedSize = mDecompressedSize; 98f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (compressedData == null && decompressedSize == 0) { 99f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa synchronized (mLockObject) { 100f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa compressedData = mCompressedData; 101f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa decompressedSize = mDecompressedSize; 102f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (compressedData == null && decompressedSize == 0) { 103f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa final byte[] decompressedData = marshall(mInstance); 104f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa compressedData = compress(decompressedData); 105f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (compressedData == null) { 106f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa decompressedSize = -1; 107f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa Slog.i(TAG, "Failed to compress data."); 108f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } else { 109f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa decompressedSize = decompressedData.length; 110f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 111f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa mDecompressedSize = decompressedSize; 112f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa mCompressedData = compressedData; 113f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 114f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 115f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 116f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 117f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (compressedData != null && decompressedSize > 0) { 118f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa dest.writeInt(mCount); 119f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa dest.writeInt(decompressedSize); 120f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa dest.writeByteArray(compressedData); 121f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } else { 122f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa Slog.i(TAG, "Unexpected state. Behaving as an empty array."); 123f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa dest.writeInt(0); 124f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 125f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 126f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 127f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa /** 128f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * Return {@link InputMethodSubtype} specified with the given index. 129f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * 130f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * <p>This methods may take a bit additional time to decompress data lazily when called 131f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * first time.</p> 132f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * 133f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * @param index The index of {@link InputMethodSubtype}. 134f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa */ 135f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa public InputMethodSubtype get(final int index) { 136f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (index < 0 || mCount <= index) { 137f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa throw new ArrayIndexOutOfBoundsException(); 138f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 139f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa InputMethodSubtype[] instance = mInstance; 140f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (instance == null) { 141f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa synchronized (mLockObject) { 142f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa instance = mInstance; 143f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (instance == null) { 144f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa final byte[] decompressedData = 145f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa decompress(mCompressedData, mDecompressedSize); 146f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa // Clear the compressed data until {@link #getMarshalled()} is called. 147f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa mCompressedData = null; 148f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa mDecompressedSize = 0; 149f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (decompressedData != null) { 150f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa instance = unmarshall(decompressedData); 151f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } else { 152f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa Slog.e(TAG, "Failed to decompress data. Returns null as fallback."); 153f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa instance = new InputMethodSubtype[mCount]; 154f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 155f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa mInstance = instance; 156f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 157f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 158f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 159f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa return instance[index]; 160f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 161f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 162f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa /** 163f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * Return the number of {@link InputMethodSubtype} objects. 164f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa */ 165f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa public int getCount() { 166f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa return mCount; 167f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 168f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 169f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa private final Object mLockObject = new Object(); 170f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa private final int mCount; 171f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 172f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa private volatile InputMethodSubtype[] mInstance; 173f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa private volatile byte[] mCompressedData; 174f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa private volatile int mDecompressedSize; 175f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 176f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa private static byte[] marshall(final InputMethodSubtype[] array) { 177f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa Parcel parcel = null; 178f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa try { 179f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa parcel = Parcel.obtain(); 180f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa parcel.writeTypedArray(array, 0); 181f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa return parcel.marshall(); 182f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } finally { 183f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (parcel != null) { 184f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa parcel.recycle(); 185f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa parcel = null; 186f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 187f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 188f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 189f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 190f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa private static InputMethodSubtype[] unmarshall(final byte[] data) { 191f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa Parcel parcel = null; 192f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa try { 193f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa parcel = Parcel.obtain(); 194f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa parcel.unmarshall(data, 0, data.length); 195f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa parcel.setDataPosition(0); 196f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa return parcel.createTypedArray(InputMethodSubtype.CREATOR); 197f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } finally { 198f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (parcel != null) { 199f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa parcel.recycle(); 200f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa parcel = null; 201f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 202f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 203f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 204f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 205f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa private static byte[] compress(final byte[] data) { 206f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa ByteArrayOutputStream resultStream = null; 207f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa GZIPOutputStream zipper = null; 208f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa try { 209f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa resultStream = new ByteArrayOutputStream(); 210f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa zipper = new GZIPOutputStream(resultStream); 211f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa zipper.write(data); 212f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } catch(IOException e) { 213f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa return null; 214f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } finally { 215f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa try { 216f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (zipper != null) { 217f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa zipper.close(); 218f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 219f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } catch (IOException e) { 220f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa zipper = null; 221f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa Slog.e(TAG, "Failed to close the stream.", e); 222f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa // swallowed, not propagated back to the caller 223f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 224f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa try { 225f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (resultStream != null) { 226f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa resultStream.close(); 227f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 228f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } catch (IOException e) { 229f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa resultStream = null; 230f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa Slog.e(TAG, "Failed to close the stream.", e); 231f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa // swallowed, not propagated back to the caller 232f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 233f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 234f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa return resultStream != null ? resultStream.toByteArray() : null; 235f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 236f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa 237f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa private static byte[] decompress(final byte[] data, final int expectedSize) { 238f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa ByteArrayInputStream inputStream = null; 239f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa GZIPInputStream unzipper = null; 240f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa try { 241f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa inputStream = new ByteArrayInputStream(data); 242f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa unzipper = new GZIPInputStream(inputStream); 243f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa final byte [] result = new byte[expectedSize]; 244f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa int totalReadBytes = 0; 245f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa while (totalReadBytes < result.length) { 246f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa final int restBytes = result.length - totalReadBytes; 247f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa final int readBytes = unzipper.read(result, totalReadBytes, restBytes); 248f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (readBytes < 0) { 249f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa break; 250f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 251f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa totalReadBytes += readBytes; 252f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 253f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (expectedSize != totalReadBytes) { 254f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa return null; 255f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 256f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa return result; 257f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } catch(IOException e) { 258f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa return null; 259f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } finally { 260f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa try { 261f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (unzipper != null) { 262f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa unzipper.close(); 263f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 264f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } catch (IOException e) { 265f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa Slog.e(TAG, "Failed to close the stream.", e); 266f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa // swallowed, not propagated back to the caller 267f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 268f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa try { 269f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa if (inputStream != null) { 270f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa inputStream.close(); 271f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 272f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } catch (IOException e) { 273f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa Slog.e(TAG, "Failed to close the stream.", e); 274f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa // swallowed, not propagated back to the caller 275f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 276f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 277f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa } 278f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa} 279