X-Git-Url: http://gitweb.fperrin.net/?a=blobdiff_plain;f=src%2Fcom%2Fhughes%2Fandroid%2Fdictionary%2FDictionaryManagerActivity.java;h=3ca7a6d9a8b1c6a5826fcb92fbb3c7f636a5049a;hb=83d497f704ad1f8ba85190255d46a3fbe0e3c353;hp=df9ab93be23fbae0c9b8f8d29f13ca234c30514c;hpb=9cb5a8e2d7acacc8e01e5133e50a225550eb0501;p=Dictionary.git diff --git a/src/com/hughes/android/dictionary/DictionaryManagerActivity.java b/src/com/hughes/android/dictionary/DictionaryManagerActivity.java index df9ab93..3ca7a6d 100644 --- a/src/com/hughes/android/dictionary/DictionaryManagerActivity.java +++ b/src/com/hughes/android/dictionary/DictionaryManagerActivity.java @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.preference.PreferenceManager; +import android.provider.Settings; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v4.view.MenuItemCompat; @@ -59,6 +60,7 @@ import android.widget.Button; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.FrameLayout; +import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.ListAdapter; import android.widget.ListView; @@ -69,6 +71,7 @@ import android.widget.ToggleButton; import com.hughes.android.dictionary.DictionaryInfo.IndexInfo; import com.hughes.android.util.IntentLauncher; +import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -77,6 +80,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -181,61 +186,80 @@ public class DictionaryManagerActivity extends ActionBarActivity { } Log.w(LOG, "Download finished: " + dest + " Id: " + downloadId); - Toast.makeText(context, getString(R.string.unzippingDictionary, dest), - Toast.LENGTH_LONG).show(); - - - final Uri zipUri = Uri.parse(dest); - File localZipFile = null; - InputStream zipFileStream = null; - ZipInputStream zipFile = null; - OutputStream zipOut = null; - try { - if (zipUri.getScheme().equals("content")) { - zipFileStream = context.getContentResolver().openInputStream(zipUri); - localZipFile = null; - } else { - localZipFile = new File(zipUri.getPath()); - zipFileStream = new FileInputStream(localZipFile); - } - zipFile = new ZipInputStream(zipFileStream); - final ZipEntry zipEntry = zipFile.getNextEntry(); - 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); - Toast.makeText(context, getString(R.string.installationFinished, dest), + 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) { - String msg = getString(R.string.unzippingFailed, dest); - File dir = application.getDictDir(); - if (!dir.canWrite() || !application.checkFileCreate(dir)) { - msg = getString(R.string.notWritable, dir.getAbsolutePath()); + 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; } - 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 e) {} - try { - if (zipFile != null) zipFile.close(); - } catch (IOException e) {} - try { - if (zipFileStream != null) zipFileStream.close(); - } catch (IOException e) {} - if (localZipFile != null) localZipFile.delete(); + throw e; } } + zipFile = new ZipInputStream(new BufferedInputStream(zipFileStream)); + final ZipEntry zipEntry = zipFile.getNextEntry(); + 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 e) {} + try { + if (zipFile != null) zipFile.close(); + } catch (IOException e) {} + try { + if (zipFileStream != null) zipFileStream.close(); + } catch (IOException e) {} + if (localZipFile != null && delete) localZipFile.delete(); } - }; + return result; + } public static Intent getLaunchIntent(Context c) { final Intent intent = new Intent(c, DictionaryManagerActivity.class); @@ -278,14 +302,16 @@ public class DictionaryManagerActivity extends ActionBarActivity { @Override public void onCreate(Bundle savedInstanceState) { - // This must be first, otherwise the actiona bar doesn't get + DictionaryApplication.INSTANCE.init(getApplicationContext()); + application = DictionaryApplication.INSTANCE; + // This must be first, otherwise the action bar doesn't get // styled properly. - setTheme(((DictionaryApplication) getApplication()).getSelectedTheme().themeId); + setTheme(application.getSelectedTheme().themeId); super.onCreate(savedInstanceState); Log.d(LOG, "onCreate:" + this); - application = (DictionaryApplication) getApplication(); + setTheme(application.getSelectedTheme().themeId); blockAutoLaunch = false; @@ -300,7 +326,7 @@ public class DictionaryManagerActivity extends ActionBarActivity { getListView().getContext()).inflate( R.layout.dictionary_manager_header_row_downloadable, getListView(), false); - showDownloadable = (ToggleButton) downloadableDictionariesHeaderRow + showDownloadable = downloadableDictionariesHeaderRow .findViewById(R.id.hideDownloadable); showDownloadable.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override @@ -324,10 +350,19 @@ public class DictionaryManagerActivity extends ActionBarActivity { setMyListAdapater(); registerForContextMenu(getListView()); + getListView().setItemsCanFocus(true); readableCheckAndError(true); onCreateSetupActionBar(); + + final Intent intent = getIntent(); + if (intent != null && intent.getAction() != null && + intent.getAction().equals(Intent.ACTION_VIEW)) { + blockAutoLaunch = true; + Uri uri = intent.getData(); + unzipInstall(this, uri, uri.getLastPathSegment(), false); + } } private void onCreateSetupActionBar() { @@ -383,16 +418,24 @@ public class DictionaryManagerActivity extends ActionBarActivity { unregisterReceiver(broadcastReceiver); } - private static int copyStream(final InputStream in, final OutputStream out) + private static void copyStream(final InputStream ins, final FileOutputStream outs) throws IOException { + ByteBuffer buf = ByteBuffer.allocateDirect(1024 * 64); + FileChannel out = outs.getChannel(); int bytesRead; - final byte[] bytes = new byte[1024 * 16]; - while ((bytesRead = in.read(bytes)) != -1) { - out.write(bytes, 0, bytesRead); - } - in.close(); - out.close(); - return bytesRead; + int pos = 0; + final byte[] bytes = new byte[1024 * 64]; + do { + bytesRead = ins.read(bytes, pos, bytes.length - pos); + if (bytesRead != -1) pos += bytesRead; + if (bytesRead == -1 ? pos != 0 : 2*pos >= bytes.length) { + buf.put(bytes, 0, pos); + pos = 0; + buf.flip(); + while (buf.hasRemaining()) out.write(buf); + buf.clear(); + } + } while (bytesRead != -1); } @Override @@ -428,18 +471,14 @@ public class DictionaryManagerActivity extends ActionBarActivity { startActivity(DictionaryActivity.getLaunchIntent(getApplicationContext(), new File(prefs.getString(C.DICT_FILE, "")), prefs.getString(C.INDEX_SHORT_NAME, ""), - prefs.getString(C.SEARCH_TOKEN, ""))); + "")); finish(); return; } // Remove the active dictionary from the prefs so we won't autolaunch // next time. - final Editor editor = prefs.edit(); - editor.remove(C.DICT_FILE); - editor.remove(C.INDEX_SHORT_NAME); - editor.remove(C.SEARCH_TOKEN); - editor.commit(); + prefs.edit().remove(C.DICT_FILE).remove(C.INDEX_SHORT_NAME).commit(); application.backgroundUpdateDictionaries(dictionaryUpdater); @@ -448,6 +487,10 @@ public class DictionaryManagerActivity extends ActionBarActivity { @Override public boolean onCreateOptionsMenu(final Menu menu) { + if ("true".equals(Settings.System.getString(getContentResolver(), "firebase.test.lab"))) + { + return false; // testing the menu is not very interesting + } final MenuItem sort = menu.add(getString(R.string.sortDicts)); MenuItemCompat.setShowAsAction(sort, MenuItem.SHOW_AS_ACTION_NEVER); sort.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @@ -458,7 +501,19 @@ public class DictionaryManagerActivity extends ActionBarActivity { } }); - application.onCreateGlobalOptionsMenu(this, menu); + final MenuItem browserDownload = menu.add(getString(R.string.browserDownload)); + MenuItemCompat.setShowAsAction(browserDownload, MenuItem.SHOW_AS_ACTION_NEVER); + browserDownload.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + public boolean onMenuItemClick(final MenuItem menuItem) { + final Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri + .parse("https://github.com/rdoeffinger/Dictionary/releases/v0.2-dictionaries")); + startActivity(intent); + return false; + } + }); + + DictionaryApplication.onCreateGlobalOptionsMenu(this, menu); return true; } @@ -568,30 +623,34 @@ public class DictionaryManagerActivity extends ActionBarActivity { } @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView instanceof LinearLayout && - convertView != dictionariesOnDeviceHeaderRow && - convertView != downloadableDictionariesHeaderRow) { - /* - * This is done to try to avoid leaking memory that used to - * happen on Android 4.0.3 - */ - ((LinearLayout) convertView).removeAllViews(); - } + public int getViewTypeCount() { + return 3; + } + @Override + public int getItemViewType(int position) { final Row row = getItem(position); + if (row.dictionaryInfo == null) { + return row.onDevice ? 0 : 1; + } + assert row.dictionaryInfo.indexInfos.size() <= 2; + return 2; + } - if (row.onDevice) { - if (row.dictionaryInfo == null) { - return dictionariesOnDeviceHeaderRow; - } - return createDictionaryRow(row.dictionaryInfo, parent, true); + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == dictionariesOnDeviceHeaderRow || + convertView == downloadableDictionariesHeaderRow) { + return convertView; } + final Row row = getItem(position); + if (row.dictionaryInfo == null) { - return downloadableDictionariesHeaderRow; + assert convertView == null; + return row.onDevice ? dictionariesOnDeviceHeaderRow : downloadableDictionariesHeaderRow; } - return createDictionaryRow(row.dictionaryInfo, parent, false); + return createDictionaryRow(row.dictionaryInfo, parent, convertView, row.onDevice); } } @@ -604,16 +663,18 @@ public class DictionaryManagerActivity extends ActionBarActivity { } private View createDictionaryRow(final DictionaryInfo dictionaryInfo, - final ViewGroup parent, boolean canLaunch) { + final ViewGroup parent, View row, boolean canLaunch) { - View row = LayoutInflater.from(parent.getContext()).inflate( + if (row == null) { + row = LayoutInflater.from(parent.getContext()).inflate( R.layout.dictionary_manager_row, parent, false); - final TextView name = (TextView) row.findViewById(R.id.dictionaryName); - final TextView details = (TextView) row.findViewById(R.id.dictionaryDetails); + } + final TextView name = row.findViewById(R.id.dictionaryName); + final TextView details = row.findViewById(R.id.dictionaryDetails); name.setText(application.getDictionaryName(dictionaryInfo.uncompressedFilename)); final boolean updateAvailable = application.updateAvailable(dictionaryInfo); - final Button downloadButton = (Button) row.findViewById(R.id.downloadButton); + final Button downloadButton = row.findViewById(R.id.downloadButton); final DictionaryInfo downloadable = application.getDownloadable(dictionaryInfo.uncompressedFilename); boolean broken = false; if (!dictionaryInfo.isValid()) { @@ -632,21 +693,31 @@ public class DictionaryManagerActivity extends ActionBarActivity { downloadDictionary(downloadable.downloadUrl, downloadable.zipBytes, downloadButton); } }); + downloadButton.setVisibility(View.VISIBLE); } else { - downloadButton.setVisibility(View.INVISIBLE); + downloadButton.setVisibility(View.GONE); } - LinearLayout buttons = (LinearLayout) row.findViewById(R.id.dictionaryLauncherButtons); + LinearLayout buttons = row.findViewById(R.id.dictionaryLauncherButtons); + final List sortedIndexInfos = application .sortedIndexInfos(dictionaryInfo.indexInfos); final StringBuilder builder = new StringBuilder(); if (updateAvailable) { builder.append(getString(R.string.updateAvailable)); } - for (IndexInfo indexInfo : sortedIndexInfos) { - final View button = application.createButton(buttons.getContext(), dictionaryInfo, - indexInfo); - buttons.addView(button); + assert buttons.getChildCount() == 4; + for (int i = 0; i < 2; i++) { + final Button textButton = (Button)buttons.getChildAt(2*i); + final ImageButton imageButton = (ImageButton)buttons.getChildAt(2*i + 1); + if (i >= sortedIndexInfos.size()) { + textButton.setVisibility(View.GONE); + imageButton.setVisibility(View.GONE); + continue; + } + final IndexInfo indexInfo = sortedIndexInfos.get(i); + final View button = IsoUtils.INSTANCE.setupButton(textButton, imageButton, dictionaryInfo, + indexInfo, application.languageButtonPixels); if (canLaunch) { button.setOnClickListener( @@ -655,9 +726,9 @@ public class DictionaryManagerActivity extends ActionBarActivity { application.getPath(dictionaryInfo.uncompressedFilename), indexInfo.shortName, ""))); - } else { - button.setEnabled(false); } + button.setEnabled(canLaunch); + button.setFocusable(canLaunch); if (builder.length() != 0) { builder.append("; "); } @@ -669,20 +740,20 @@ public class DictionaryManagerActivity extends ActionBarActivity { if (broken) { name.setText("Broken: " + application.getDictionaryName(dictionaryInfo.uncompressedFilename)); builder.append("; Cannot be used, redownload, check hardware/file system"); - // Allow deleting, but cannot open - row.setLongClickable(true); } details.setText(builder.toString()); if (canLaunch) { - row.setClickable(true); row.setOnClickListener(new IntentLauncher(parent.getContext(), DictionaryActivity.getLaunchIntent(getApplicationContext(), application.getPath(dictionaryInfo.uncompressedFilename), dictionaryInfo.indexInfos.get(0).shortName, ""))); - row.setFocusable(true); - row.setLongClickable(true); + // do not setFocusable, for keyboard navigation + // offering only the index buttons is better. } + row.setClickable(canLaunch); + // Allow deleting, even if we cannot open + row.setLongClickable(broken || canLaunch); row.setBackgroundResource(android.R.drawable.menuitem_background); return row; @@ -703,8 +774,9 @@ public class DictionaryManagerActivity extends ActionBarActivity { // Due to a bug, cursor is null instead of empty when // the download manager is disabled. if (cursor == null) { + String msg = getString(R.string.downloadManagerQueryFailed); new AlertDialog.Builder(DictionaryManagerActivity.this).setTitle(getString(R.string.error)) - .setMessage(getString(R.string.downloadFailed, R.string.downloadManagerQueryFailed)) + .setMessage(getString(R.string.downloadFailed, msg)) .setNeutralButton("Close", null).show(); return; }