Home | History | Annotate | Download | only in internal
      1 /*
      2  * Copyright (C) 2012 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.inputmethod.keyboard.internal;
     18 
     19 import android.content.Context;
     20 import android.content.res.Resources;
     21 import android.text.TextUtils;
     22 
     23 import com.android.inputmethod.annotations.UsedForTesting;
     24 import com.android.inputmethod.latin.Constants;
     25 import com.android.inputmethod.latin.utils.RunInLocale;
     26 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
     27 
     28 import java.util.HashMap;
     29 import java.util.Locale;
     30 
     31 public final class KeyboardTextsSet {
     32     public static final String PREFIX_TEXT = "!text/";
     33     public static final String SWITCH_TO_ALPHA_KEY_LABEL = "keylabel_to_alpha";
     34 
     35     private static final char BACKSLASH = Constants.CODE_BACKSLASH;
     36     private static final int MAX_STRING_REFERENCE_INDIRECTION = 10;
     37 
     38     private String[] mTextsTable;
     39     // Resource name to text map.
     40     private HashMap<String, String> mResourceNameToTextsMap = new HashMap<>();
     41 
     42     public void setLocale(final Locale locale, final Context context) {
     43         mTextsTable = KeyboardTextsTable.getTextsTable(locale);
     44         final Resources res = context.getResources();
     45         final int referenceId = context.getApplicationInfo().labelRes;
     46         final String resourcePackageName = res.getResourcePackageName(referenceId);
     47         final RunInLocale<Void> job = new RunInLocale<Void>() {
     48             @Override
     49             protected Void job(final Resources resource) {
     50                 loadStringResourcesInternal(res, RESOURCE_NAMES, resourcePackageName);
     51                 return null;
     52             }
     53         };
     54         // Null means the current system locale.
     55         job.runInLocale(res,
     56                 SubtypeLocaleUtils.NO_LANGUAGE.equals(locale.toString()) ? null : locale);
     57     }
     58 
     59     @UsedForTesting
     60     void loadStringResourcesInternal(final Resources res, final String[] resourceNames,
     61             final String resourcePackageName) {
     62         for (final String resName : resourceNames) {
     63             final int resId = res.getIdentifier(resName, "string", resourcePackageName);
     64             mResourceNameToTextsMap.put(resName, res.getString(resId));
     65         }
     66     }
     67 
     68     public String getText(final String name) {
     69         final String text = mResourceNameToTextsMap.get(name);
     70         return (text != null) ? text : KeyboardTextsTable.getText(name, mTextsTable);
     71     }
     72 
     73     private static int searchTextNameEnd(final String text, final int start) {
     74         final int size = text.length();
     75         for (int pos = start; pos < size; pos++) {
     76             final char c = text.charAt(pos);
     77             // Label name should be consisted of [a-zA-Z_0-9].
     78             if ((c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')) {
     79                 continue;
     80             }
     81             return pos;
     82         }
     83         return size;
     84     }
     85 
     86     // TODO: Resolve text reference when creating {@link KeyboardTextsTable} class.
     87     public String resolveTextReference(final String rawText) {
     88         if (TextUtils.isEmpty(rawText)) {
     89             return null;
     90         }
     91         int level = 0;
     92         String text = rawText;
     93         StringBuilder sb;
     94         do {
     95             level++;
     96             if (level >= MAX_STRING_REFERENCE_INDIRECTION) {
     97                 throw new RuntimeException("Too many " + PREFIX_TEXT + "name indirection: " + text);
     98             }
     99 
    100             final int prefixLen = PREFIX_TEXT.length();
    101             final int size = text.length();
    102             if (size < prefixLen) {
    103                 break;
    104             }
    105 
    106             sb = null;
    107             for (int pos = 0; pos < size; pos++) {
    108                 final char c = text.charAt(pos);
    109                 if (text.startsWith(PREFIX_TEXT, pos)) {
    110                     if (sb == null) {
    111                         sb = new StringBuilder(text.substring(0, pos));
    112                     }
    113                     final int end = searchTextNameEnd(text, pos + prefixLen);
    114                     final String name = text.substring(pos + prefixLen, end);
    115                     sb.append(getText(name));
    116                     pos = end - 1;
    117                 } else if (c == BACKSLASH) {
    118                     if (sb != null) {
    119                         // Append both escape character and escaped character.
    120                         sb.append(text.substring(pos, Math.min(pos + 2, size)));
    121                     }
    122                     pos++;
    123                 } else if (sb != null) {
    124                     sb.append(c);
    125                 }
    126             }
    127 
    128             if (sb != null) {
    129                 text = sb.toString();
    130             }
    131         } while (sb != null);
    132         return TextUtils.isEmpty(text) ? null : text;
    133     }
    134 
    135     // These texts' name should be aligned with the @string/<name> in
    136     // values*/strings-action-keys.xml.
    137     static final String[] RESOURCE_NAMES = {
    138         // Labels for action.
    139         "label_go_key",
    140         "label_send_key",
    141         "label_next_key",
    142         "label_done_key",
    143         "label_search_key",
    144         "label_previous_key",
    145         // Other labels.
    146         "label_pause_key",
    147         "label_wait_key",
    148     };
    149 }
    150