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 static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertNotSame; 22 import static org.junit.Assert.assertTrue; 23 24 import android.annotation.NonNull; 25 import android.content.pm.ApplicationInfo; 26 import android.content.pm.ResolveInfo; 27 import android.content.pm.ServiceInfo; 28 import android.os.Parcel; 29 import android.platform.test.annotations.Presubmit; 30 import android.view.inputmethod.InputMethodInfo; 31 32 import androidx.test.ext.junit.runners.AndroidJUnit4; 33 import androidx.test.filters.SmallTest; 34 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 import java.util.ArrayList; 39 import java.util.Collections; 40 import java.util.List; 41 import java.util.function.Function; 42 43 @SmallTest 44 @Presubmit 45 @RunWith(AndroidJUnit4.class) 46 public final class InputMethodInfoSafeListTest { 47 48 @NonNull createFakeInputMethodInfo(String packageName, String name)49 private static InputMethodInfo createFakeInputMethodInfo(String packageName, String name) { 50 final ResolveInfo ri = new ResolveInfo(); 51 final ServiceInfo si = new ServiceInfo(); 52 final ApplicationInfo ai = new ApplicationInfo(); 53 ai.packageName = packageName; 54 ai.enabled = true; 55 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 56 si.applicationInfo = ai; 57 si.enabled = true; 58 si.packageName = packageName; 59 si.name = name; 60 si.exported = true; 61 si.nonLocalizedLabel = name; 62 ri.serviceInfo = si; 63 return new InputMethodInfo(ri, false, "", Collections.emptyList(), 1, false); 64 } 65 66 @NonNull createTestInputMethodList()67 private static List<InputMethodInfo> createTestInputMethodList() { 68 final ArrayList<InputMethodInfo> list = new ArrayList<>(); 69 list.add(createFakeInputMethodInfo("com.android.test.ime1", "TestIme1")); 70 list.add(createFakeInputMethodInfo("com.android.test.ime1", "TestIme2")); 71 list.add(createFakeInputMethodInfo("com.android.test.ime2", "TestIme")); 72 return list; 73 } 74 75 @Test testCreate()76 public void testCreate() { 77 assertNotNull(InputMethodInfoSafeList.create(createTestInputMethodList())); 78 } 79 80 @Test testExtract()81 public void testExtract() { 82 assertItemsAfterExtract(createTestInputMethodList(), InputMethodInfoSafeList::create); 83 } 84 85 @Test testExtractAfterParceling()86 public void testExtractAfterParceling() { 87 assertItemsAfterExtract(createTestInputMethodList(), 88 originals -> cloneViaParcel(InputMethodInfoSafeList.create(originals))); 89 } 90 91 @Test testExtractEmptyList()92 public void testExtractEmptyList() { 93 assertItemsAfterExtract(Collections.emptyList(), InputMethodInfoSafeList::create); 94 } 95 96 @Test testExtractAfterParcelingEmptyList()97 public void testExtractAfterParcelingEmptyList() { 98 assertItemsAfterExtract(Collections.emptyList(), 99 originals -> cloneViaParcel(InputMethodInfoSafeList.create(originals))); 100 } 101 assertItemsAfterExtract(@onNull List<InputMethodInfo> originals, @NonNull Function<List<InputMethodInfo>, InputMethodInfoSafeList> factory)102 private static void assertItemsAfterExtract(@NonNull List<InputMethodInfo> originals, 103 @NonNull Function<List<InputMethodInfo>, InputMethodInfoSafeList> factory) { 104 final InputMethodInfoSafeList list = factory.apply(originals); 105 final List<InputMethodInfo> extracted = InputMethodInfoSafeList.extractFrom(list); 106 assertEquals(originals.size(), extracted.size()); 107 for (int i = 0; i < originals.size(); ++i) { 108 assertNotSame("InputMethodInfoSafeList.extractFrom() must clone each instance", 109 originals.get(i), extracted.get(i)); 110 assertEquals("Verify the cloned instances have the equal value", 111 originals.get(i).getPackageName(), extracted.get(i).getPackageName()); 112 } 113 114 // Subsequent calls of InputMethodInfoSafeList.extractFrom() return an empty list. 115 final List<InputMethodInfo> extracted2 = InputMethodInfoSafeList.extractFrom(list); 116 assertTrue(extracted2.isEmpty()); 117 } 118 119 @NonNull cloneViaParcel( @onNull InputMethodInfoSafeList original)120 private static InputMethodInfoSafeList cloneViaParcel( 121 @NonNull InputMethodInfoSafeList original) { 122 Parcel parcel = null; 123 try { 124 parcel = Parcel.obtain(); 125 original.writeToParcel(parcel, 0); 126 parcel.setDataPosition(0); 127 final InputMethodInfoSafeList newInstance = 128 InputMethodInfoSafeList.CREATOR.createFromParcel(parcel); 129 assertNotNull(newInstance); 130 return newInstance; 131 } finally { 132 if (parcel != null) { 133 parcel.recycle(); 134 } 135 } 136 } 137 } 138