1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.inputmethod; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.view.inputmethod.InputMethodInfo; 24 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 import java.util.List; 28 29 /** 30 * A {@link Parcelable} container that can holds an arbitrary number of {@link InputMethodInfo} 31 * without worrying about {@link android.os.TransactionTooLargeException} when passing across 32 * process boundary. 33 * 34 * @see Parcel#readBlob() 35 * @see Parcel#writeBlob(byte[]) 36 */ 37 public final class InputMethodInfoSafeList implements Parcelable { 38 @Nullable 39 private byte[] mBuffer; 40 41 /** 42 * Instantiates a list of {@link InputMethodInfo} from the given {@link InputMethodInfoSafeList} 43 * then clears the internal buffer of {@link InputMethodInfoSafeList}. 44 * 45 * <p>Note that each {@link InputMethodInfo} item is guaranteed to be a copy of the original 46 * {@link InputMethodInfo} object.</p> 47 * 48 * <p>Any subsequent call will return an empty list.</p> 49 * 50 * @param from {@link InputMethodInfoSafeList} from which the list of {@link InputMethodInfo} 51 * will be extracted 52 * @return list of {@link InputMethodInfo} stored in the given {@link InputMethodInfoSafeList} 53 */ 54 @NonNull extractFrom(@ullable InputMethodInfoSafeList from)55 public static List<InputMethodInfo> extractFrom(@Nullable InputMethodInfoSafeList from) { 56 final byte[] buf = from.mBuffer; 57 from.mBuffer = null; 58 if (buf != null) { 59 final InputMethodInfo[] array = unmarshall(buf); 60 if (array != null) { 61 return new ArrayList<>(Arrays.asList(array)); 62 } 63 } 64 return new ArrayList<>(); 65 } 66 67 @NonNull toArray(@ullable List<InputMethodInfo> original)68 private static InputMethodInfo[] toArray(@Nullable List<InputMethodInfo> original) { 69 if (original == null) { 70 return new InputMethodInfo[0]; 71 } 72 return original.toArray(new InputMethodInfo[0]); 73 } 74 75 @Nullable marshall(@onNull InputMethodInfo[] array)76 private static byte[] marshall(@NonNull InputMethodInfo[] array) { 77 Parcel parcel = null; 78 try { 79 parcel = Parcel.obtain(); 80 parcel.writeTypedArray(array, 0); 81 return parcel.marshall(); 82 } finally { 83 if (parcel != null) { 84 parcel.recycle(); 85 } 86 } 87 } 88 89 @Nullable unmarshall(byte[] data)90 private static InputMethodInfo[] unmarshall(byte[] data) { 91 Parcel parcel = null; 92 try { 93 parcel = Parcel.obtain(); 94 parcel.unmarshall(data, 0, data.length); 95 parcel.setDataPosition(0); 96 return parcel.createTypedArray(InputMethodInfo.CREATOR); 97 } finally { 98 if (parcel != null) { 99 parcel.recycle(); 100 } 101 } 102 } 103 InputMethodInfoSafeList(@ullable byte[] blob)104 private InputMethodInfoSafeList(@Nullable byte[] blob) { 105 mBuffer = blob; 106 } 107 108 /** 109 * Instantiates {@link InputMethodInfoSafeList} from the given list of {@link InputMethodInfo}. 110 * 111 * @param list list of {@link InputMethodInfo} from which {@link InputMethodInfoSafeList} will 112 * be created 113 * @return {@link InputMethodInfoSafeList} that stores the given list of {@link InputMethodInfo} 114 */ 115 @NonNull create(@ullable List<InputMethodInfo> list)116 public static InputMethodInfoSafeList create(@Nullable List<InputMethodInfo> list) { 117 if (list == null || list.isEmpty()) { 118 return empty(); 119 } 120 return new InputMethodInfoSafeList(marshall(toArray(list))); 121 } 122 123 /** 124 * Creates an empty {@link InputMethodInfoSafeList}. 125 * 126 * @return {@link InputMethodInfoSafeList} that is empty 127 */ 128 @NonNull empty()129 public static InputMethodInfoSafeList empty() { 130 return new InputMethodInfoSafeList(null); 131 } 132 133 public static final Creator<InputMethodInfoSafeList> CREATOR = new Creator<>() { 134 @Override 135 public InputMethodInfoSafeList createFromParcel(Parcel in) { 136 return new InputMethodInfoSafeList(in.readBlob()); 137 } 138 139 @Override 140 public InputMethodInfoSafeList[] newArray(int size) { 141 return new InputMethodInfoSafeList[size]; 142 } 143 }; 144 145 @Override describeContents()146 public int describeContents() { 147 // As long as InputMethodInfo#describeContents() is guaranteed to return 0, we can always 148 // return 0 here. 149 return 0; 150 } 151 152 @Override writeToParcel(Parcel dest, int flags)153 public void writeToParcel(Parcel dest, int flags) { 154 dest.writeBlob(mBuffer); 155 } 156 } 157