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
17package com.android.inputmethod.latin.debug;
18
19import android.app.AlertDialog;
20import android.content.Context;
21import android.content.DialogInterface;
22import android.content.DialogInterface.OnCancelListener;
23import android.content.DialogInterface.OnClickListener;
24import android.os.Environment;
25
26import com.android.inputmethod.latin.BinaryDictionaryFileDumper;
27import com.android.inputmethod.latin.BinaryDictionaryGetter;
28import com.android.inputmethod.latin.R;
29import com.android.inputmethod.latin.makedict.DictionaryHeader;
30import com.android.inputmethod.latin.utils.DialogUtils;
31import com.android.inputmethod.latin.utils.DictionaryInfoUtils;
32import com.android.inputmethod.latin.utils.LocaleUtils;
33
34import java.io.BufferedInputStream;
35import java.io.BufferedOutputStream;
36import java.io.File;
37import java.io.FileInputStream;
38import java.io.FileOutputStream;
39import java.io.IOException;
40import java.util.ArrayList;
41import java.util.Locale;
42
43/**
44 * A class to read a local file as a dictionary for debugging purposes.
45 */
46public 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 = new ArrayList<>();
53        for (File f : files) {
54            final DictionaryHeader 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(DialogUtils.getPlatformDialogThemeContext(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        new AlertDialog.Builder(DialogUtils.getPlatformDialogThemeContext(context))
85                .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 DictionaryHeader 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(DialogUtils.getPlatformDialogThemeContext(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 DictionaryHeader 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(DialogUtils.getPlatformDialogThemeContext(context))
171                    .setTitle(R.string.read_external_dictionary_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