1 /* 2 * Copyright (C) 2013 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.debug; 18 19 import android.app.AlertDialog; 20 import android.content.Context; 21 import android.content.DialogInterface; 22 import android.content.DialogInterface.OnCancelListener; 23 import android.content.DialogInterface.OnClickListener; 24 import android.os.Environment; 25 26 import com.android.inputmethod.latin.BinaryDictionaryFileDumper; 27 import com.android.inputmethod.latin.BinaryDictionaryGetter; 28 import com.android.inputmethod.latin.R; 29 import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; 30 import com.android.inputmethod.latin.utils.CollectionUtils; 31 import com.android.inputmethod.latin.utils.DictionaryInfoUtils; 32 import com.android.inputmethod.latin.utils.LocaleUtils; 33 34 import java.io.BufferedInputStream; 35 import java.io.BufferedOutputStream; 36 import java.io.File; 37 import java.io.FileInputStream; 38 import java.io.FileOutputStream; 39 import java.io.IOException; 40 import java.util.ArrayList; 41 import java.util.Locale; 42 43 /** 44 * A class to read a local file as a dictionary for debugging purposes. 45 */ 46 public class ExternalDictionaryGetterForDebug { 47 private static final String SOURCE_FOLDER = Environment.getExternalStorageDirectory().getPath() 48 + "/Download"; 49 50 private static String[] findDictionariesInTheDownloadedFolder() { 51 final File[] files = new File(SOURCE_FOLDER).listFiles(); 52 final ArrayList<String> eligibleList = CollectionUtils.newArrayList(); 53 for (File f : files) { 54 final FileHeader header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(f); 55 if (null == header) continue; 56 eligibleList.add(f.getName()); 57 } 58 return eligibleList.toArray(new String[0]); 59 } 60 61 public static void chooseAndInstallDictionary(final Context context) { 62 final String[] fileNames = findDictionariesInTheDownloadedFolder(); 63 if (0 == fileNames.length) { 64 showNoFileDialog(context); 65 } else if (1 == fileNames.length) { 66 askInstallFile(context, SOURCE_FOLDER, fileNames[0], null /* completeRunnable */); 67 } else { 68 showChooseFileDialog(context, fileNames); 69 } 70 } 71 72 private static void showNoFileDialog(final Context context) { 73 new AlertDialog.Builder(context) 74 .setMessage(R.string.read_external_dictionary_no_files_message) 75 .setPositiveButton(android.R.string.ok, new OnClickListener() { 76 @Override 77 public void onClick(final DialogInterface dialog, final int which) { 78 dialog.dismiss(); 79 } 80 }).create().show(); 81 } 82 83 private static void showChooseFileDialog(final Context context, final String[] fileNames) { 84 final AlertDialog.Builder builder = new AlertDialog.Builder(context); 85 builder.setTitle(R.string.read_external_dictionary_multiple_files_title) 86 .setItems(fileNames, new OnClickListener() { 87 @Override 88 public void onClick(final DialogInterface dialog, final int which) { 89 askInstallFile(context, SOURCE_FOLDER, fileNames[which], 90 null /* completeRunnable */); 91 } 92 }) 93 .create().show(); 94 } 95 96 /** 97 * Shows a dialog which offers the user to install the external dictionary. 98 */ 99 public static void askInstallFile(final Context context, final String dirPath, 100 final String fileName, final Runnable completeRunnable) { 101 final File file = new File(dirPath, fileName.toString()); 102 final FileHeader header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(file); 103 final StringBuilder message = new StringBuilder(); 104 final String locale = header.getLocaleString(); 105 for (String key : header.mDictionaryOptions.mAttributes.keySet()) { 106 message.append(key + " = " + header.mDictionaryOptions.mAttributes.get(key)); 107 message.append("\n"); 108 } 109 final String languageName = LocaleUtils.constructLocaleFromString(locale) 110 .getDisplayName(Locale.getDefault()); 111 final String title = String.format( 112 context.getString(R.string.read_external_dictionary_confirm_install_message), 113 languageName); 114 new AlertDialog.Builder(context) 115 .setTitle(title) 116 .setMessage(message) 117 .setNegativeButton(android.R.string.cancel, new OnClickListener() { 118 @Override 119 public void onClick(final DialogInterface dialog, final int which) { 120 dialog.dismiss(); 121 if (completeRunnable != null) { 122 completeRunnable.run(); 123 } 124 } 125 }).setPositiveButton(android.R.string.ok, new OnClickListener() { 126 @Override 127 public void onClick(final DialogInterface dialog, final int which) { 128 installFile(context, file, header); 129 dialog.dismiss(); 130 if (completeRunnable != null) { 131 completeRunnable.run(); 132 } 133 } 134 }).setOnCancelListener(new OnCancelListener() { 135 @Override 136 public void onCancel(DialogInterface dialog) { 137 // Canceled by the user by hitting the back key 138 if (completeRunnable != null) { 139 completeRunnable.run(); 140 } 141 } 142 }).create().show(); 143 } 144 145 private static void installFile(final Context context, final File file, 146 final FileHeader header) { 147 BufferedOutputStream outputStream = null; 148 File tempFile = null; 149 try { 150 final String locale = header.getLocaleString(); 151 // Create the id for a main dictionary for this locale 152 final String id = BinaryDictionaryGetter.MAIN_DICTIONARY_CATEGORY 153 + BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR + locale; 154 final String finalFileName = DictionaryInfoUtils.getCacheFileName(id, locale, context); 155 final String tempFileName = BinaryDictionaryGetter.getTempFileName(id, context); 156 tempFile = new File(tempFileName); 157 tempFile.delete(); 158 outputStream = new BufferedOutputStream(new FileOutputStream(tempFile)); 159 final BufferedInputStream bufferedStream = new BufferedInputStream( 160 new FileInputStream(file)); 161 BinaryDictionaryFileDumper.checkMagicAndCopyFileTo(bufferedStream, outputStream); 162 outputStream.flush(); 163 final File finalFile = new File(finalFileName); 164 finalFile.delete(); 165 if (!tempFile.renameTo(finalFile)) { 166 throw new IOException("Can't move the file to its final name"); 167 } 168 } catch (IOException e) { 169 // There was an error: show a dialog 170 new AlertDialog.Builder(context) 171 .setTitle(R.string.error) 172 .setMessage(e.toString()) 173 .setPositiveButton(android.R.string.ok, new OnClickListener() { 174 @Override 175 public void onClick(final DialogInterface dialog, final int which) { 176 dialog.dismiss(); 177 } 178 }).create().show(); 179 return; 180 } finally { 181 try { 182 if (null != outputStream) outputStream.close(); 183 if (null != tempFile) tempFile.delete(); 184 } catch (IOException e) { 185 // Don't do anything 186 } 187 } 188 } 189 } 190