Home | History | Annotate | Download | only in latin
      1 /*
      2  * Copyright (C) 2011 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.latin;
     18 
     19 import android.content.Context;
     20 import android.content.res.AssetFileDescriptor;
     21 import android.content.res.Resources;
     22 import android.util.Log;
     23 
     24 import java.io.File;
     25 import java.util.ArrayList;
     26 import java.util.LinkedList;
     27 import java.util.Locale;
     28 
     29 /**
     30  * Factory for dictionary instances.
     31  */
     32 public final class DictionaryFactory {
     33     private static final String TAG = DictionaryFactory.class.getSimpleName();
     34 
     35     /**
     36      * Initializes a main dictionary collection from a dictionary pack, with explicit flags.
     37      *
     38      * This searches for a content provider providing a dictionary pack for the specified
     39      * locale. If none is found, it falls back to the built-in dictionary - if any.
     40      * @param context application context for reading resources
     41      * @param locale the locale for which to create the dictionary
     42      * @param useFullEditDistance whether to use the full edit distance in suggestions
     43      * @return an initialized instance of DictionaryCollection
     44      */
     45     public static DictionaryCollection createMainDictionaryFromManager(final Context context,
     46             final Locale locale, final boolean useFullEditDistance) {
     47         if (null == locale) {
     48             Log.e(TAG, "No locale defined for dictionary");
     49             return new DictionaryCollection(Dictionary.TYPE_MAIN,
     50                     createBinaryDictionary(context, locale));
     51         }
     52 
     53         final LinkedList<Dictionary> dictList = CollectionUtils.newLinkedList();
     54         final ArrayList<AssetFileAddress> assetFileList =
     55                 BinaryDictionaryGetter.getDictionaryFiles(locale, context);
     56         if (null != assetFileList) {
     57             for (final AssetFileAddress f : assetFileList) {
     58                 final BinaryDictionary binaryDictionary = new BinaryDictionary(f.mFilename,
     59                         f.mOffset, f.mLength, useFullEditDistance, locale, Dictionary.TYPE_MAIN);
     60                 if (binaryDictionary.isValidDictionary()) {
     61                     dictList.add(binaryDictionary);
     62                 }
     63             }
     64         }
     65 
     66         // If the list is empty, that means we should not use any dictionary (for example, the user
     67         // explicitly disabled the main dictionary), so the following is okay. dictList is never
     68         // null, but if for some reason it is, DictionaryCollection handles it gracefully.
     69         return new DictionaryCollection(Dictionary.TYPE_MAIN, dictList);
     70     }
     71 
     72     /**
     73      * Initializes a main dictionary collection from a dictionary pack, with default flags.
     74      *
     75      * This searches for a content provider providing a dictionary pack for the specified
     76      * locale. If none is found, it falls back to the built-in dictionary, if any.
     77      * @param context application context for reading resources
     78      * @param locale the locale for which to create the dictionary
     79      * @return an initialized instance of DictionaryCollection
     80      */
     81     public static DictionaryCollection createMainDictionaryFromManager(final Context context,
     82             final Locale locale) {
     83         return createMainDictionaryFromManager(context, locale, false /* useFullEditDistance */);
     84     }
     85 
     86     /**
     87      * Initializes a dictionary from a raw resource file
     88      * @param context application context for reading resources
     89      * @param locale the locale to use for the resource
     90      * @return an initialized instance of BinaryDictionary
     91      */
     92     protected static BinaryDictionary createBinaryDictionary(final Context context,
     93             final Locale locale) {
     94         AssetFileDescriptor afd = null;
     95         try {
     96             final int resId = DictionaryInfoUtils.getMainDictionaryResourceIdIfAvailableForLocale(
     97                     context.getResources(), locale);
     98             if (0 == resId) return null;
     99             afd = context.getResources().openRawResourceFd(resId);
    100             if (afd == null) {
    101                 Log.e(TAG, "Found the resource but it is compressed. resId=" + resId);
    102                 return null;
    103             }
    104             final String sourceDir = context.getApplicationInfo().sourceDir;
    105             final File packagePath = new File(sourceDir);
    106             // TODO: Come up with a way to handle a directory.
    107             if (!packagePath.isFile()) {
    108                 Log.e(TAG, "sourceDir is not a file: " + sourceDir);
    109                 return null;
    110             }
    111             return new BinaryDictionary(sourceDir, afd.getStartOffset(), afd.getLength(),
    112                     false /* useFullEditDistance */, locale, Dictionary.TYPE_MAIN);
    113         } catch (android.content.res.Resources.NotFoundException e) {
    114             Log.e(TAG, "Could not find the resource");
    115             return null;
    116         } finally {
    117             if (null != afd) {
    118                 try {
    119                     afd.close();
    120                 } catch (java.io.IOException e) {
    121                     /* IOException on close ? What am I supposed to do ? */
    122                 }
    123             }
    124         }
    125     }
    126 
    127     /**
    128      * Create a dictionary from passed data. This is intended for unit tests only.
    129      * @param dictionary the file to read
    130      * @param startOffset the offset in the file where the data starts
    131      * @param length the length of the data
    132      * @param useFullEditDistance whether to use the full edit distance in suggestions
    133      * @return the created dictionary, or null.
    134      */
    135     public static Dictionary createDictionaryForTest(File dictionary, long startOffset, long length,
    136             final boolean useFullEditDistance, Locale locale) {
    137         if (dictionary.isFile()) {
    138             return new BinaryDictionary(dictionary.getAbsolutePath(), startOffset, length,
    139                     useFullEditDistance, locale, Dictionary.TYPE_MAIN);
    140         } else {
    141             Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath());
    142             return null;
    143         }
    144     }
    145 
    146     /**
    147      * Find out whether a dictionary is available for this locale.
    148      * @param context the context on which to check resources.
    149      * @param locale the locale to check for.
    150      * @return whether a (non-placeholder) dictionary is available or not.
    151      */
    152     public static boolean isDictionaryAvailable(Context context, Locale locale) {
    153         final Resources res = context.getResources();
    154         return 0 != DictionaryInfoUtils.getMainDictionaryResourceIdIfAvailableForLocale(
    155                 res, locale);
    156     }
    157 }
    158