InputMethodSubtypeArray.java revision a1d49337fb3ff4b336cddb1198658778b0e8949b
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) {
206a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa        try (final ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
207a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa                final GZIPOutputStream zipper = new GZIPOutputStream(resultStream)) {
208f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            zipper.write(data);
209a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa            zipper.finish();
210a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa            return resultStream.toByteArray();
211a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa        } catch(Exception e) {
212a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa            Slog.e(TAG, "Failed to compress the data.", e);
213f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            return null;
214f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
215f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    }
216f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
217f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    private static byte[] decompress(final byte[] data, final int expectedSize) {
218a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa        try (final ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
219a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa                final GZIPInputStream unzipper = new GZIPInputStream(inputStream)) {
220f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            final byte [] result = new byte[expectedSize];
221f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            int totalReadBytes = 0;
222f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            while (totalReadBytes < result.length) {
223f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                final int restBytes = result.length - totalReadBytes;
224f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                final int readBytes = unzipper.read(result, totalReadBytes, restBytes);
225f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                if (readBytes < 0) {
226f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    break;
227f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                }
228f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                totalReadBytes += readBytes;
229f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            }
230f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            if (expectedSize != totalReadBytes) {
231f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                return null;
232f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            }
233f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            return result;
234a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa        } catch(Exception e) {
235a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa            Slog.e(TAG, "Failed to decompress the data.", e);
236f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            return null;
237f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
238f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    }
239f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa}
240