+ private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public synchronized void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+
+ if (DownloadManager.ACTION_NOTIFICATION_CLICKED.equals(action)) {
+ startActivity(DictionaryManagerActivity.getLaunchIntent(getApplicationContext()).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP));
+ }
+ if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
+ final long downloadId = intent.getLongExtra(
+ DownloadManager.EXTRA_DOWNLOAD_ID, 0);
+ if (finishedDownloadIds.contains(downloadId)) return; // ignore double notifications
+ final DownloadManager.Query query = new DownloadManager.Query();
+ query.setFilterById(downloadId);
+ final DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
+ final Cursor cursor = downloadManager.query(query);
+
+ if (cursor == null || !cursor.moveToFirst()) {
+ Log.e(LOG, "Couldn't find download.");
+ return;
+ }
+
+ final String dest = cursor
+ .getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
+ final int status = cursor
+ .getInt(cursor
+ .getColumnIndex(DownloadManager.COLUMN_STATUS));
+ if (DownloadManager.STATUS_SUCCESSFUL != status) {
+ final int reason = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_REASON));
+ Log.w(LOG,
+ "Download failed: status=" + status +
+ ", reason=" + reason);
+ String msg = Integer.toString(reason);
+ switch (reason) {
+ case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
+ msg = "File exists";
+ break;
+ case DownloadManager.ERROR_FILE_ERROR:
+ msg = "File error";
+ break;
+ case DownloadManager.ERROR_INSUFFICIENT_SPACE:
+ msg = "Not enough space";
+ break;
+ }
+ new AlertDialog.Builder(context).setTitle(getString(R.string.error)).setMessage(getString(R.string.downloadFailed, msg)).setNeutralButton("Close", null).show();
+ return;
+ }
+
+ Log.w(LOG, "Download finished: " + dest + " Id: " + downloadId);
+ if (!isFinishing())
+ Toast.makeText(context, getString(R.string.unzippingDictionary, dest),
+ Toast.LENGTH_LONG).show();
+
+ if (unzipInstall(context, Uri.parse(dest), dest, true)) {
+ finishedDownloadIds.add(downloadId);
+ Log.w(LOG, "Unzipping finished: " + dest + " Id: " + downloadId);
+ }
+ }
+ }
+ };
+
+ private boolean unzipInstall(Context context, Uri zipUri, String dest, boolean delete) {
+ File localZipFile = null;
+ InputStream zipFileStream = null;
+ ZipInputStream zipFile = null;
+ FileOutputStream zipOut = null;
+ boolean result = false;
+ try {
+ if (zipUri.getScheme().equals("content")) {
+ zipFileStream = context.getContentResolver().openInputStream(zipUri);
+ localZipFile = null;
+ } else {
+ localZipFile = new File(zipUri.getPath());
+ try {
+ zipFileStream = new FileInputStream(localZipFile);
+ } catch (Exception e) {
+ if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions(this,
+ new String[] {Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE
+ }, 0);
+ return false;
+ }
+ throw e;
+ }
+ }
+ zipFile = new ZipInputStream(new BufferedInputStream(zipFileStream));
+ ZipEntry zipEntry;
+ while ((zipEntry = zipFile.getNextEntry()) != null) {
+ // Note: this check prevents security issues like accidental path
+ // traversal, which unfortunately ZipInputStream has no protection against.
+ // So take extra care when changing it.
+ if (!Pattern.matches("[-A-Za-z]+\\.quickdic", zipEntry.getName())) {
+ Log.w(LOG, "Invalid zip entry: " + zipEntry.getName());
+ continue;
+ }
+ Log.d(LOG, "Unzipping entry: " + zipEntry.getName());
+ File targetFile = new File(application.getDictDir(), zipEntry.getName());
+ if (targetFile.exists()) {
+ targetFile.renameTo(new File(targetFile.getAbsolutePath().replace(".quickdic", ".bak.quickdic")));
+ targetFile = new File(application.getDictDir(), zipEntry.getName());
+ }
+ zipOut = new FileOutputStream(targetFile);
+ copyStream(zipFile, zipOut);
+ }
+ application.backgroundUpdateDictionaries(dictionaryUpdater);
+ if (!isFinishing())
+ Toast.makeText(context, getString(R.string.installationFinished, dest),
+ Toast.LENGTH_LONG).show();
+ result = true;
+ } catch (Exception e) {
+ String msg = getString(R.string.unzippingFailed, dest + ": " + e.getMessage());
+ File dir = application.getDictDir();
+ if (!dir.canWrite() || !DictionaryApplication.checkFileCreate(dir)) {
+ msg = getString(R.string.notWritable, dir.getAbsolutePath());
+ }
+ new AlertDialog.Builder(context).setTitle(getString(R.string.error)).setMessage(msg).setNeutralButton("Close", null).show();
+ Log.e(LOG, "Failed to unzip.", e);
+ } finally {
+ try {
+ if (zipOut != null) zipOut.close();
+ } catch (IOException ignored) {}
+ try {
+ if (zipFile != null) zipFile.close();
+ } catch (IOException ignored) {}
+ try {
+ if (zipFileStream != null) zipFileStream.close();
+ } catch (IOException ignored) {}
+ if (localZipFile != null && delete) //noinspection ResultOfMethodCallIgnored
+ localZipFile.delete();
+ }
+ return result;
+ }