• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.server.inputmethod;
18 
19 import android.annotation.AnyThread;
20 import android.annotation.IntRange;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.util.ArrayMap;
24 import android.view.inputmethod.InputMethodInfo;
25 
26 import java.util.Arrays;
27 import java.util.List;
28 
29 /**
30  * A map from IME ID to {@link InputMethodInfo}, which is guaranteed to be immutable thus
31  * thread-safe.
32  */
33 final class InputMethodMap {
34     private static final ArrayMap<String, InputMethodInfo> EMPTY_MAP =
35             new ArrayMap<>();
36 
37     private final ArrayMap<String, InputMethodInfo> mMap;
38 
emptyMap()39     static InputMethodMap emptyMap() {
40         return new InputMethodMap(EMPTY_MAP);
41     }
42 
of(@onNull ArrayMap<String, InputMethodInfo> map)43     static InputMethodMap of(@NonNull ArrayMap<String, InputMethodInfo> map) {
44         return new InputMethodMap(map);
45     }
46 
InputMethodMap(@onNull ArrayMap<String, InputMethodInfo> map)47     private InputMethodMap(@NonNull ArrayMap<String, InputMethodInfo> map) {
48         mMap = map.isEmpty() ? EMPTY_MAP : new ArrayMap<>(map);
49     }
50 
51     @AnyThread
52     @Nullable
get(@ullable String imeId)53     InputMethodInfo get(@Nullable String imeId) {
54         return mMap.get(imeId);
55     }
56 
57     @AnyThread
58     @NonNull
values()59     List<InputMethodInfo> values() {
60         return List.copyOf(mMap.values());
61     }
62 
63     @AnyThread
64     @Nullable
valueAt(int index)65     InputMethodInfo valueAt(int index) {
66         return mMap.valueAt(index);
67     }
68 
69     @AnyThread
containsKey(@ullable String imeId)70     boolean containsKey(@Nullable String imeId) {
71         return mMap.containsKey(imeId);
72     }
73 
74     @AnyThread
75     @IntRange(from = 0)
size()76     int size() {
77         return mMap.size();
78     }
79 
80     @AnyThread
81     @NonNull
applyAdditionalSubtypes( @onNull AdditionalSubtypeMap additionalSubtypeMap)82     public InputMethodMap applyAdditionalSubtypes(
83             @NonNull AdditionalSubtypeMap additionalSubtypeMap) {
84         if (additionalSubtypeMap.isEmpty()) {
85             return this;
86         }
87         final int size = size();
88         final ArrayMap<String, InputMethodInfo> newMethodMap = new ArrayMap<>(size);
89         boolean updated = false;
90         for (int i = 0; i < size; ++i) {
91             final var imi = valueAt(i);
92             final var imeId = imi.getId();
93             final var newAdditionalSubtypes = additionalSubtypeMap.get(imeId);
94             if (newAdditionalSubtypes == null || newAdditionalSubtypes.isEmpty()) {
95                 newMethodMap.put(imi.getId(), imi);
96             } else {
97                 newMethodMap.put(imi.getId(), new InputMethodInfo(imi, newAdditionalSubtypes));
98                 updated = true;
99             }
100         }
101         return updated ? InputMethodMap.of(newMethodMap) : this;
102     }
103 
104     /**
105      * Compares the given two {@link InputMethodMap} instances to see if they contain the same data
106      * or not.
107      *
108      * @param map1 {@link InputMethodMap} to be compared with
109      * @param map2 {@link InputMethodMap} to be compared with
110      * @return {@code true} if both {@link InputMethodMap} instances contain exactly the same data
111      */
112     @AnyThread
areSame(@onNull InputMethodMap map1, @NonNull InputMethodMap map2)113     static boolean areSame(@NonNull InputMethodMap map1, @NonNull InputMethodMap map2) {
114         if (map1 == map2) {
115             return true;
116         }
117         final int size = map1.size();
118         if (size != map2.size()) {
119             return false;
120         }
121         for (int i = 0; i < size; ++i) {
122             final var imi1 = map1.valueAt(i);
123             final var imeId = imi1.getId();
124             final var imi2 = map2.get(imeId);
125             if (imi2 == null) {
126                 return false;
127             }
128             final var marshaled1 = InputMethodInfoUtils.marshal(imi1);
129             final var marshaled2 = InputMethodInfoUtils.marshal(imi2);
130             if (!Arrays.equals(marshaled1, marshaled2)) {
131                 return false;
132             }
133         }
134         return true;
135     }
136 }
137