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.util.Slog;
21f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
22f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.io.ByteArrayInputStream;
23f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.io.ByteArrayOutputStream;
24f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.util.List;
25f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.util.zip.GZIPInputStream;
26f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawaimport java.util.zip.GZIPOutputStream;
27f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
28f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa/**
29f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * An array-like container that stores multiple instances of {@link InputMethodSubtype}.
30f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa *
31f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * <p>This container is designed to reduce the risk of {@link TransactionTooLargeException}
32f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * when one or more instancess of {@link InputMethodInfo} are transferred through IPC.
33f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * Basically this class does following three tasks.</p>
34f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * <ul>
35f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * <li>Applying compression for the marshalled data</li>
36f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * <li>Lazily unmarshalling objects</li>
37f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * <li>Caching the marshalled data when appropriate</li>
38f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * </ul>
39f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa *
40f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa * @hide
41f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa */
42f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawapublic class InputMethodSubtypeArray {
43f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    private final static String TAG = "InputMethodSubtypeArray";
44f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
45f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    /**
46f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * Create a new instance of {@link InputMethodSubtypeArray} from an existing list of
47f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * {@link InputMethodSubtype}.
48f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     *
49f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * @param subtypes A list of {@link InputMethodSubtype} from which
50f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * {@link InputMethodSubtypeArray} will be created.
51f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     */
52f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    public InputMethodSubtypeArray(final List<InputMethodSubtype> subtypes) {
53f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        if (subtypes == null) {
54f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            mCount = 0;
55f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            return;
56f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
57f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        mCount = subtypes.size();
58f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        mInstance = subtypes.toArray(new InputMethodSubtype[mCount]);
59f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    }
60f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
61f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    /**
62f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * Unmarshall an instance of {@link InputMethodSubtypeArray} from a given {@link Parcel}
63f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * object.
64f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     *
65f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * @param source A {@link Parcel} object from which {@link InputMethodSubtypeArray} will be
66f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * unmarshalled.
67f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     */
68f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    public InputMethodSubtypeArray(final Parcel source) {
69f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        mCount = source.readInt();
70f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        if (mCount > 0) {
71f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            mDecompressedSize = source.readInt();
72f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            mCompressedData = source.createByteArray();
73f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
74f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    }
75f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
76f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    /**
77f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * Marshall the instance into a given {@link Parcel} object.
78f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     *
79f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * <p>This methods may take a bit additional time to compress data lazily when called
80f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * first time.</p>
81f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     *
82f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * @param source A {@link Parcel} object to which {@link InputMethodSubtypeArray} will be
83f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * marshalled.
84f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     */
85f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    public void writeToParcel(final Parcel dest) {
86f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        if (mCount == 0) {
87f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            dest.writeInt(mCount);
88f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            return;
89f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
90f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
91f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        byte[] compressedData = mCompressedData;
92f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        int decompressedSize = mDecompressedSize;
93f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        if (compressedData == null && decompressedSize == 0) {
94f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            synchronized (mLockObject) {
95f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                compressedData = mCompressedData;
96f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                decompressedSize = mDecompressedSize;
97f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                if (compressedData == null && decompressedSize == 0) {
98f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    final byte[] decompressedData = marshall(mInstance);
99f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    compressedData = compress(decompressedData);
100f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    if (compressedData == null) {
101f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                        decompressedSize = -1;
102f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                        Slog.i(TAG, "Failed to compress data.");
103f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    } else {
104f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                        decompressedSize = decompressedData.length;
105f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    }
106f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    mDecompressedSize = decompressedSize;
107f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    mCompressedData = compressedData;
108f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                }
109f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            }
110f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
111f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
112f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        if (compressedData != null && decompressedSize > 0) {
113f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            dest.writeInt(mCount);
114f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            dest.writeInt(decompressedSize);
115f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            dest.writeByteArray(compressedData);
116f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        } else {
117f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            Slog.i(TAG, "Unexpected state. Behaving as an empty array.");
118f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            dest.writeInt(0);
119f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
120f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    }
121f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
122f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    /**
123f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * Return {@link InputMethodSubtype} specified with the given index.
124f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     *
125f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * <p>This methods may take a bit additional time to decompress data lazily when called
126f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * first time.</p>
127f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     *
128f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * @param index The index of {@link InputMethodSubtype}.
129f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     */
130f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    public InputMethodSubtype get(final int index) {
131f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        if (index < 0 || mCount <= index) {
132f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            throw new ArrayIndexOutOfBoundsException();
133f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
134f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        InputMethodSubtype[] instance = mInstance;
135f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        if (instance == null) {
136f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            synchronized (mLockObject) {
137f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                instance = mInstance;
138f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                if (instance == null) {
139f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    final byte[] decompressedData =
140f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                          decompress(mCompressedData, mDecompressedSize);
141f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    // Clear the compressed data until {@link #getMarshalled()} is called.
142f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    mCompressedData = null;
143f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    mDecompressedSize = 0;
144f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    if (decompressedData != null) {
145f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                        instance = unmarshall(decompressedData);
146f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    } else {
147f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                        Slog.e(TAG, "Failed to decompress data. Returns null as fallback.");
148f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                        instance = new InputMethodSubtype[mCount];
149f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    }
150f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    mInstance = instance;
151f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                }
152f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            }
153f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
154f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        return instance[index];
155f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    }
156f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
157f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    /**
158f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     * Return the number of {@link InputMethodSubtype} objects.
159f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa     */
160f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    public int getCount() {
161f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        return mCount;
162f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    }
163f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
164f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    private final Object mLockObject = new Object();
165f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    private final int mCount;
166f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
167f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    private volatile InputMethodSubtype[] mInstance;
168f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    private volatile byte[] mCompressedData;
169f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    private volatile int mDecompressedSize;
170f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
171f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    private static byte[] marshall(final InputMethodSubtype[] array) {
172f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        Parcel parcel = null;
173f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        try {
174f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            parcel = Parcel.obtain();
175f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            parcel.writeTypedArray(array, 0);
176f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            return parcel.marshall();
177f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        } finally {
178f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            if (parcel != null) {
179f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                parcel.recycle();
180f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                parcel = null;
181f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            }
182f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
183f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    }
184f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
185f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    private static InputMethodSubtype[] unmarshall(final byte[] data) {
186f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        Parcel parcel = null;
187f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        try {
188f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            parcel = Parcel.obtain();
189f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            parcel.unmarshall(data, 0, data.length);
190f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            parcel.setDataPosition(0);
191f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            return parcel.createTypedArray(InputMethodSubtype.CREATOR);
192f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        } finally {
193f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            if (parcel != null) {
194f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                parcel.recycle();
195f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                parcel = null;
196f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            }
197f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
198f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    }
199f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
200f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    private static byte[] compress(final byte[] data) {
201a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa        try (final ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
202a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa                final GZIPOutputStream zipper = new GZIPOutputStream(resultStream)) {
203f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            zipper.write(data);
204a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa            zipper.finish();
205a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa            return resultStream.toByteArray();
206a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa        } catch(Exception e) {
207a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa            Slog.e(TAG, "Failed to compress the data.", e);
208f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            return null;
209f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
210f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    }
211f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa
212f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    private static byte[] decompress(final byte[] data, final int expectedSize) {
213a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa        try (final ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
214a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa                final GZIPInputStream unzipper = new GZIPInputStream(inputStream)) {
215f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            final byte [] result = new byte[expectedSize];
216f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            int totalReadBytes = 0;
217f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            while (totalReadBytes < result.length) {
218f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                final int restBytes = result.length - totalReadBytes;
219f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                final int readBytes = unzipper.read(result, totalReadBytes, restBytes);
220f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                if (readBytes < 0) {
221f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                    break;
222f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                }
223f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                totalReadBytes += readBytes;
224f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            }
225f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            if (expectedSize != totalReadBytes) {
226f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa                return null;
227f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            }
228f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            return result;
229a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa        } catch(Exception e) {
230a1d49337fb3ff4b336cddb1198658778b0e8949bYohei Yukawa            Slog.e(TAG, "Failed to decompress the data.", e);
231f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa            return null;
232f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa        }
233f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa    }
234f06569561fe1c6e898debf8bb9f37331a9f87323Yohei Yukawa}
235