1 /*
2  * Copyright (C) 2022 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.assertNotEquals;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertSame;
23 import static org.junit.Assert.assertThrows;
24 
25 import android.annotation.NonNull;
26 import android.content.ComponentName;
27 import android.os.Parcel;
28 import android.platform.test.annotations.Presubmit;
29 import android.view.inputmethod.InputMethodInfo;
30 import android.view.inputmethod.InputMethodSubtype;
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.security.InvalidParameterException;
39 
40 @SmallTest
41 @Presubmit
42 @RunWith(AndroidJUnit4.class)
43 public class InputMethodSubtypeHandleTest {
44 
45     @Test
testCreateFromRawHandle()46     public void testCreateFromRawHandle() {
47         {
48             final InputMethodSubtypeHandle handle =
49                     InputMethodSubtypeHandle.of("com.android.test/.Ime1:subtype:1");
50             assertNotNull(handle);
51             assertEquals("com.android.test/.Ime1:subtype:1", handle.toStringHandle());
52             assertEquals("com.android.test/.Ime1", handle.getImeId());
53             assertEquals(ComponentName.unflattenFromString("com.android.test/.Ime1"),
54                     handle.getComponentName());
55         }
56 
57         assertThrows(NullPointerException.class, () -> InputMethodSubtypeHandle.of(null));
58         assertThrows(InvalidParameterException.class, () -> InputMethodSubtypeHandle.of(""));
59 
60         // The IME ID must use ComponentName#flattenToShortString(), not #flattenToString().
61         assertThrows(InvalidParameterException.class, () -> InputMethodSubtypeHandle.of(
62                 "com.android.test/com.android.test.Ime1:subtype:1"));
63 
64         assertThrows(InvalidParameterException.class, () -> InputMethodSubtypeHandle.of(
65                 "com.android.test/.Ime1:subtype:0001"));
66         assertThrows(InvalidParameterException.class, () -> InputMethodSubtypeHandle.of(
67                 "com.android.test/.Ime1:subtype:1!"));
68         assertThrows(InvalidParameterException.class, () -> InputMethodSubtypeHandle.of(
69                 "com.android.test/.Ime1:subtype:1:"));
70         assertThrows(InvalidParameterException.class, () -> InputMethodSubtypeHandle.of(
71                 "com.android.test/.Ime1:subtype:1:2"));
72         assertThrows(InvalidParameterException.class, () -> InputMethodSubtypeHandle.of(
73                 "com.android.test/.Ime1:subtype:a"));
74         assertThrows(InvalidParameterException.class, () -> InputMethodSubtypeHandle.of(
75                 "com.android.test/.Ime1:subtype:0x01"));
76         assertThrows(InvalidParameterException.class, () -> InputMethodSubtypeHandle.of(
77                 "com.android.test/.Ime1:Subtype:a"));
78         assertThrows(InvalidParameterException.class, () -> InputMethodSubtypeHandle.of(
79                 "ime1:subtype:1"));
80     }
81 
82     @Test
testCreateFromInputMethodInfo()83     public void testCreateFromInputMethodInfo() {
84         final InputMethodInfo imi = new InputMethodInfo(
85                 "com.android.test", "com.android.test.Ime1", "TestIME", null);
86         {
87             final InputMethodSubtypeHandle handle = InputMethodSubtypeHandle.of(imi, null);
88             assertNotNull(handle);
89             assertEquals("com.android.test/.Ime1:subtype:0", handle.toStringHandle());
90             assertEquals("com.android.test/.Ime1", handle.getImeId());
91             assertEquals(ComponentName.unflattenFromString("com.android.test/.Ime1"),
92                     handle.getComponentName());
93         }
94 
95         final InputMethodSubtype subtype =
96                 new InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(1).build();
97         {
98             final InputMethodSubtypeHandle handle = InputMethodSubtypeHandle.of(imi, subtype);
99             assertNotNull(handle);
100             assertEquals("com.android.test/.Ime1:subtype:1", handle.toStringHandle());
101             assertEquals("com.android.test/.Ime1", handle.getImeId());
102             assertEquals(ComponentName.unflattenFromString("com.android.test/.Ime1"),
103                     handle.getComponentName());
104         }
105 
106         assertThrows(NullPointerException.class, () -> InputMethodSubtypeHandle.of(null, null));
107         assertThrows(NullPointerException.class, () -> InputMethodSubtypeHandle.of(null, subtype));
108     }
109 
110     @Test
testEquality()111     public void testEquality() {
112         assertEquals(InputMethodSubtypeHandle.of("com.android.test/.Ime1:subtype:1"),
113                 InputMethodSubtypeHandle.of("com.android.test/.Ime1:subtype:1"));
114         assertEquals(InputMethodSubtypeHandle.of("com.android.test/.Ime1:subtype:1").hashCode(),
115                 InputMethodSubtypeHandle.of("com.android.test/.Ime1:subtype:1").hashCode());
116 
117         assertNotEquals(InputMethodSubtypeHandle.of("com.android.test/.Ime1:subtype:1"),
118                 InputMethodSubtypeHandle.of("com.android.test/.Ime1:subtype:2"));
119         assertNotEquals(InputMethodSubtypeHandle.of("com.android.test/.Ime1:subtype:1"),
120                 InputMethodSubtypeHandle.of("com.android.test/.Ime2:subtype:1"));
121     }
122 
123     @Test
testParcelablility()124     public void testParcelablility() {
125         final InputMethodSubtypeHandle original =
126                 InputMethodSubtypeHandle.of("com.android.test/.Ime1:subtype:1");
127         final InputMethodSubtypeHandle cloned = cloneHandle(original);
128         assertEquals(original, cloned);
129         assertEquals(original.hashCode(), cloned.hashCode());
130         assertEquals(original.getComponentName(), cloned.getComponentName());
131         assertEquals(original.getImeId(), cloned.getImeId());
132         assertEquals(original.toStringHandle(), cloned.toStringHandle());
133     }
134 
135     @Test
testNoUnnecessaryStringInstantiationInToStringHandle()136     public void testNoUnnecessaryStringInstantiationInToStringHandle() {
137         final String validHandleStr = "com.android.test/.Ime1:subtype:1";
138         // Verify that toStringHandle() returns the same String object if the input is valid for
139         // an efficient memory usage.
140         assertSame(validHandleStr, InputMethodSubtypeHandle.of(validHandleStr).toStringHandle());
141     }
142 
143     @NonNull
cloneHandle( @onNull InputMethodSubtypeHandle original)144     private static InputMethodSubtypeHandle cloneHandle(
145             @NonNull InputMethodSubtypeHandle original) {
146         Parcel parcel = null;
147         try {
148             parcel = Parcel.obtain();
149             original.writeToParcel(parcel, 0);
150             parcel.setDataPosition(0);
151             return InputMethodSubtypeHandle.CREATOR.createFromParcel(parcel);
152         } finally {
153             if (parcel != null) {
154                 parcel.recycle();
155             }
156         }
157     }
158 }
159