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 17 package com.android.inputmethod.dictionarypack; 18 19 import android.content.Context; 20 import android.database.Cursor; 21 22 import java.io.IOException; 23 import java.io.InputStreamReader; 24 import java.util.Collections; 25 import java.util.ArrayList; 26 import java.util.List; 27 28 /** 29 * Helper class to easy up manipulation of dictionary pack metadata. 30 */ 31 public class MetadataHandler { 32 @SuppressWarnings("unused") 33 private static final String TAG = "DictionaryProvider:" + MetadataHandler.class.getSimpleName(); 34 35 // The canonical file name for metadata. This is not the name of a real file on the 36 // device, but a symbolic name used in the database and in metadata handling. It is never 37 // tested against, only used for human-readability as the file name for the metadata. 38 public final static String METADATA_FILENAME = "metadata.json"; 39 40 /** 41 * Reads the data from the cursor and store it in metadata objects. 42 * @param results the cursor to read data from. 43 * @return the constructed list of wordlist metadata. 44 */ 45 private static List<WordListMetadata> makeMetadataObject(final Cursor results) { 46 final ArrayList<WordListMetadata> buildingMetadata = new ArrayList<>(); 47 if (null != results && results.moveToFirst()) { 48 final int localeColumn = results.getColumnIndex(MetadataDbHelper.LOCALE_COLUMN); 49 final int typeColumn = results.getColumnIndex(MetadataDbHelper.TYPE_COLUMN); 50 final int descriptionColumn = 51 results.getColumnIndex(MetadataDbHelper.DESCRIPTION_COLUMN); 52 final int idIndex = results.getColumnIndex(MetadataDbHelper.WORDLISTID_COLUMN); 53 final int updateIndex = results.getColumnIndex(MetadataDbHelper.DATE_COLUMN); 54 final int fileSizeIndex = results.getColumnIndex(MetadataDbHelper.FILESIZE_COLUMN); 55 final int rawChecksumIndex = 56 results.getColumnIndex(MetadataDbHelper.RAW_CHECKSUM_COLUMN); 57 final int checksumIndex = results.getColumnIndex(MetadataDbHelper.CHECKSUM_COLUMN); 58 final int localFilenameIndex = 59 results.getColumnIndex(MetadataDbHelper.LOCAL_FILENAME_COLUMN); 60 final int remoteFilenameIndex = 61 results.getColumnIndex(MetadataDbHelper.REMOTE_FILENAME_COLUMN); 62 final int versionIndex = results.getColumnIndex(MetadataDbHelper.VERSION_COLUMN); 63 final int formatVersionIndex = 64 results.getColumnIndex(MetadataDbHelper.FORMATVERSION_COLUMN); 65 do { 66 buildingMetadata.add(new WordListMetadata(results.getString(idIndex), 67 results.getInt(typeColumn), 68 results.getString(descriptionColumn), 69 results.getLong(updateIndex), 70 results.getLong(fileSizeIndex), 71 results.getString(rawChecksumIndex), 72 results.getString(checksumIndex), 73 results.getString(localFilenameIndex), 74 results.getString(remoteFilenameIndex), 75 results.getInt(versionIndex), 76 results.getInt(formatVersionIndex), 77 0, results.getString(localeColumn))); 78 } while (results.moveToNext()); 79 } 80 return Collections.unmodifiableList(buildingMetadata); 81 } 82 83 /** 84 * Gets the whole metadata, for installed and not installed dictionaries. 85 * @param context The context to open files over. 86 * @param clientId the client id for retrieving the database. null for default (deprecated) 87 * @return The current metadata. 88 */ 89 public static List<WordListMetadata> getCurrentMetadata(final Context context, 90 final String clientId) { 91 // If clientId is null, we get a cursor on the default database (see 92 // MetadataDbHelper#getInstance() for more on this) 93 final Cursor results = MetadataDbHelper.queryCurrentMetadata(context, clientId); 94 // If null, we should return makeMetadataObject(null), so we go through. 95 try { 96 return makeMetadataObject(results); 97 } finally { 98 if (null != results) { 99 results.close(); 100 } 101 } 102 } 103 104 /** 105 * Read metadata from a stream. 106 * @param input The stream to read from. 107 * @return The read metadata. 108 * @throws IOException if the input stream cannot be read 109 * @throws BadFormatException if the stream is not in a known format 110 */ 111 public static List<WordListMetadata> readMetadata(final InputStreamReader input) 112 throws IOException, BadFormatException { 113 return MetadataParser.parseMetadata(input); 114 } 115 116 /** 117 * Finds a single WordListMetadata inside a whole metadata chunk. 118 * 119 * Searches through the whole passed metadata for the first WordListMetadata associated 120 * with the passed ID. If several metadata chunks with the same id are found, it will 121 * always return the one with the bigger FormatVersion that is less or equal than the 122 * maximum supported format version (as listed in UpdateHandler). 123 * This will NEVER return the metadata with a FormatVersion bigger than what is supported, 124 * even if it is the only word list with this ID. 125 * 126 * @param metadata the metadata to search into. 127 * @param id the word list ID of the metadata to find. 128 * @return the associated metadata, or null if not found. 129 */ 130 public static WordListMetadata findWordListById(final List<WordListMetadata> metadata, 131 final String id) { 132 WordListMetadata bestWordList = null; 133 int bestFormatVersion = Integer.MIN_VALUE; // To be sure we can't be inadvertently smaller 134 for (WordListMetadata wordList : metadata) { 135 if (id.equals(wordList.mId) 136 && wordList.mFormatVersion <= UpdateHandler.MAXIMUM_SUPPORTED_FORMAT_VERSION 137 && wordList.mFormatVersion > bestFormatVersion) { 138 bestWordList = wordList; 139 bestFormatVersion = wordList.mFormatVersion; 140 } 141 } 142 // If we didn't find any match we'll return null. 143 return bestWordList; 144 } 145 } 146