DictionaryFactory.java revision 19bfef6cb0714a46a276abe45329e4abb661f76e
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17package com.android.inputmethod.latin; 18 19import android.content.Context; 20import android.content.res.AssetFileDescriptor; 21import android.content.res.Configuration; 22import android.content.res.Resources; 23import android.util.Log; 24 25import java.io.File; 26import java.util.Locale; 27 28/** 29 * Factory for dictionary instances. 30 */ 31public class DictionaryFactory { 32 33 private static String TAG = DictionaryFactory.class.getSimpleName(); 34 35 /** 36 * Initializes a dictionary from a dictionary pack. 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 using the resource passed as fallBackResId 40 * as a dictionary. 41 * @param context application context for reading resources 42 * @param locale the locale for which to create the dictionary 43 * @param fallbackResId the id of the resource to use as a fallback if no pack is found 44 * @return an initialized instance of Dictionary 45 */ 46 public static Dictionary createDictionaryFromManager(Context context, Locale locale, 47 int fallbackResId) { 48 if (null == locale) { 49 Log.e(TAG, "No locale defined for dictionary"); 50 return new DictionaryCollection(createBinaryDictionary(context, fallbackResId)); 51 } 52 53 final AssetFileAddress dictFile = BinaryDictionaryGetter.getDictionaryFile(locale, 54 context, fallbackResId); 55 if (null == dictFile) return null; 56 return new DictionaryCollection(new BinaryDictionary(context, 57 dictFile.mFilename, dictFile.mOffset, dictFile.mLength, null)); 58 } 59 60 /** 61 * Initializes a dictionary from a raw resource file 62 * @param context application context for reading resources 63 * @param resId the resource containing the raw binary dictionary 64 * @return an initialized instance of BinaryDictionary 65 */ 66 protected static BinaryDictionary createBinaryDictionary(Context context, int resId) { 67 AssetFileDescriptor afd = null; 68 try { 69 // TODO: IMPORTANT: Do not create a dictionary from a placeholder. 70 afd = context.getResources().openRawResourceFd(resId); 71 if (afd == null) { 72 Log.e(TAG, "Found the resource but it is compressed. resId=" + resId); 73 return null; 74 } 75 if (!isFullDictionary(afd)) return null; 76 final String sourceDir = context.getApplicationInfo().sourceDir; 77 final File packagePath = new File(sourceDir); 78 // TODO: Come up with a way to handle a directory. 79 if (!packagePath.isFile()) { 80 Log.e(TAG, "sourceDir is not a file: " + sourceDir); 81 return null; 82 } 83 return new BinaryDictionary(context, 84 sourceDir, afd.getStartOffset(), afd.getLength(), null); 85 } catch (android.content.res.Resources.NotFoundException e) { 86 Log.e(TAG, "Could not find the resource. resId=" + resId); 87 return null; 88 } finally { 89 if (null != afd) { 90 try { 91 afd.close(); 92 } catch (java.io.IOException e) { 93 /* IOException on close ? What am I supposed to do ? */ 94 } 95 } 96 } 97 } 98 99 /** 100 * Create a dictionary from passed data. This is intended for unit tests only. 101 * @param context the test context to create this data from. 102 * @param dictionary the file to read 103 * @param startOffset the offset in the file where the data starts 104 * @param length the length of the data 105 * @param flagArray the flags to use with this data for testing 106 * @return the created dictionary, or null. 107 */ 108 public static Dictionary createDictionaryForTest(Context context, File dictionary, 109 long startOffset, long length, Flag[] flagArray) { 110 if (dictionary.isFile()) { 111 return new BinaryDictionary(context, dictionary.getAbsolutePath(), startOffset, length, 112 flagArray); 113 } else { 114 Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath()); 115 return null; 116 } 117 } 118 119 /** 120 * Find out whether a dictionary is available for this locale. 121 * @param context the context on which to check resources. 122 * @param locale the locale to check for. 123 * @return whether a (non-placeholder) dictionary is available or not. 124 */ 125 public static boolean isDictionaryAvailable(Context context, Locale locale) { 126 final Resources res = context.getResources(); 127 final Locale saveLocale = Utils.setSystemLocale(res, locale); 128 129 final int resourceId = Utils.getMainDictionaryResourceId(res); 130 final AssetFileDescriptor afd = res.openRawResourceFd(resourceId); 131 final boolean hasDictionary = isFullDictionary(afd); 132 try { 133 if (null != afd) afd.close(); 134 } catch (java.io.IOException e) { 135 /* Um, what can we do here exactly? */ 136 } 137 138 Utils.setSystemLocale(res, saveLocale); 139 return hasDictionary; 140 } 141 142 // TODO: Find the Right Way to find out whether the resource is a placeholder or not. 143 // Suggestion : strip the locale, open the placeholder file and store its offset. 144 // Upon opening the file, if it's the same offset, then it's the placeholder. 145 private static final long PLACEHOLDER_LENGTH = 34; 146 /** 147 * Finds out whether the data pointed out by an AssetFileDescriptor is a full 148 * dictionary (as opposed to null, or to a place holder). 149 * @param afd the file descriptor to test, or null 150 * @return true if the dictionary is a real full dictionary, false if it's null or a placeholder 151 */ 152 protected static boolean isFullDictionary(final AssetFileDescriptor afd) { 153 return (afd != null && afd.getLength() > PLACEHOLDER_LENGTH); 154 } 155} 156