package yuku.alkitab.base.ac; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.support.v7.app.ActionBar; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import com.afollestad.materialdialogs.MaterialDialog; import com.squareup.picasso.Callback; import yuku.afw.V; import yuku.afw.widget.EasyAdapter; import yuku.alkitab.base.App; import yuku.alkitab.base.ac.base.BaseActivity; import yuku.alkitab.base.sv.DownloadService; import yuku.alkitab.base.util.Background; import yuku.alkitab.base.util.FontManager; import yuku.alkitab.base.util.Foreground; import yuku.alkitab.debug.BuildConfig; import yuku.alkitab.debug.R; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Scanner; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; public class FontManagerActivity extends BaseActivity implements DownloadService.DownloadListener { public static final String TAG = FontManagerActivity.class.getSimpleName(); private static final String URL_fontList = BuildConfig.SERVER_HOST + "addon/fonts/v1/list-v2.txt"; private static final String URL_fontData = BuildConfig.SERVER_HOST + "addon/fonts/v1/data/%s.zip"; private static final String URL_fontPreview = BuildConfig.SERVER_HOST + "addon/fonts/v1/preview/%s-384x84.png"; public static Intent createIntent() { return new Intent(App.context, FontManagerActivity.class); } ListView lsFont; FontAdapter adapter; View progress; TextView lEmptyError; DownloadService dls; private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { dls = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { dls = ((DownloadService.DownloadBinder) service).getService(); dls.setDownloadListener(FontManagerActivity.this); runOnUiThread(() -> loadFontList()); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.willNeedStoragePermission(); super.onCreate(savedInstanceState); setContentView(R.layout.activity_font_manager); final Toolbar toolbar = V.get(this, R.id.toolbar); setSupportActionBar(toolbar); final ActionBar ab = getSupportActionBar(); assert ab != null; ab.setDisplayHomeAsUpEnabled(true); lsFont = V.get(this, R.id.lsFont); progress = V.get(this, R.id.progress); lEmptyError = V.get(this, R.id.lEmptyError); lsFont.setAdapter(adapter = new FontAdapter()); bindService(new Intent(App.context, DownloadService.class), serviceConnection, BIND_AUTO_CREATE); } @Override protected void onNeededPermissionsGranted(final boolean immediatelyGranted) { super.onNeededPermissionsGranted(immediatelyGranted); if (!immediatelyGranted && dls != null) { loadFontList(); } } @Override protected void onDestroy() { super.onDestroy(); if (dls != null) { unbindService(serviceConnection); } } void loadFontList() { Background.run(() -> { try { final String listString = App.downloadString(URL_fontList); final List<FontItem> list = new ArrayList<>(); final Scanner sc = new Scanner(listString); if (sc.hasNextLine() && sc.nextLine().startsWith("OK")) { while (sc.hasNextLine()) { String line = sc.nextLine().trim(); if (line.length() > 0) { FontItem item = new FontItem(); item.name = line.split(" ")[0]; list.add(item); } } } Foreground.run(() -> { adapter.setData(list); lEmptyError.setVisibility(View.GONE); progress.setVisibility(View.GONE); }); } catch (IOException e) { final String errorMsg = e.getMessage(); Foreground.run(() -> { lEmptyError.setVisibility(View.VISIBLE); lEmptyError.setText(errorMsg); progress.setVisibility(View.GONE); }); } }); } String getFontDownloadKey(String name) { return "FontManager/" + name; } private String getFontNameFromDownloadKey(String key) { if (!key.startsWith("FontManager/")) return null; return key.substring("FontManager/".length()); } String getFontDownloadDestination(String name) { return new File(getCacheDir(), "download-" + name + ".zip").getAbsolutePath(); } public static class FontItem { public String name; } public class FontAdapter extends EasyAdapter { final List<FontItem> list = new ArrayList<>(); public void setData(List<FontItem> list) { this.list.clear(); this.list.addAll(list); notifyDataSetChanged(); } @Override public int getCount() { return list.size(); } @Override public FontItem getItem(int position) { return list.get(position); } @Override public View newView(final int position, final ViewGroup parent) { return getLayoutInflater().inflate(R.layout.item_font_download, parent, false); } @Override public void bindView(final View view, final int position, final ViewGroup parent) { final ImageView imgPreview = V.get(view, R.id.imgPreview); final TextView lFontName = V.get(view, R.id.lFontName); final View bDownload = V.get(view, R.id.bDownload); final View bDelete = V.get(view, R.id.bDelete); final ProgressBar progressbar = V.get(view, R.id.progressbar); final TextView lErrorMsg = V.get(view, R.id.lErrorMsg); final FontItem item = getItem(position); final String dlkey = getFontDownloadKey(item.name); lFontName.setText(item.name); lFontName.setVisibility(View.VISIBLE); App.picasso().load(String.format(URL_fontPreview, item.name)).into(imgPreview, new Callback.EmptyCallback() { @Override public void onSuccess() { lFontName.setVisibility(View.GONE); } }); imgPreview.setContentDescription(item.name); bDownload.setTag(R.id.TAG_fontItem, item); bDownload.setOnClickListener(bDownload_click); bDelete.setTag(R.id.TAG_fontItem, item); bDelete.setOnClickListener(bDelete_click); if (FontManager.isInstalled(item.name)) { progressbar.setIndeterminate(false); progressbar.setMax(100); progressbar.setProgress(100); bDownload.setVisibility(View.GONE); bDelete.setVisibility(View.VISIBLE); lErrorMsg.setVisibility(View.GONE); } else { DownloadService.DownloadEntry entry = dls.getEntry(dlkey); if (entry == null) { progressbar.setIndeterminate(false); progressbar.setMax(100); progressbar.setProgress(0); bDownload.setVisibility(View.VISIBLE); bDownload.setEnabled(true); bDelete.setVisibility(View.GONE); lErrorMsg.setVisibility(View.GONE); } else { if (entry.state == DownloadService.State.created) { progressbar.setIndeterminate(true); bDownload.setVisibility(View.VISIBLE); bDownload.setEnabled(false); bDelete.setVisibility(View.GONE); lErrorMsg.setVisibility(View.GONE); } else if (entry.state == DownloadService.State.downloading) { if (entry.length == -1) { progressbar.setIndeterminate(true); } else { progressbar.setIndeterminate(false); progressbar.setMax((int) entry.length); progressbar.setProgress((int) entry.progress); } bDownload.setVisibility(View.VISIBLE); bDownload.setEnabled(false); bDelete.setVisibility(View.GONE); lErrorMsg.setVisibility(View.GONE); } else if (entry.state == DownloadService.State.finished) { progressbar.setIndeterminate(false); progressbar.setMax(100); // consider full progressbar.setProgress(100); // consider full bDownload.setVisibility(View.GONE); bDelete.setVisibility(View.VISIBLE); lErrorMsg.setVisibility(View.GONE); } else if (entry.state == DownloadService.State.failed) { progressbar.setIndeterminate(false); progressbar.setMax(100); progressbar.setProgress(0); bDownload.setVisibility(View.VISIBLE); bDownload.setEnabled(true); bDelete.setVisibility(View.GONE); lErrorMsg.setVisibility(View.VISIBLE); lErrorMsg.setText(entry.errorMsg); } } } } private View.OnClickListener bDownload_click = v -> { FontItem item = (FontItem) v.getTag(R.id.TAG_fontItem); String dlkey = getFontDownloadKey(item.name); dls.removeEntry(dlkey); if (dls.getEntry(dlkey) == null) { dls.startDownload( dlkey, String.format(URL_fontData, item.name), getFontDownloadDestination(item.name) ); } notifyDataSetChanged(); }; private View.OnClickListener bDelete_click = v -> { final FontItem item = (FontItem) v.getTag(R.id.TAG_fontItem); new MaterialDialog.Builder(FontManagerActivity.this) .content(getString(R.string.fm_do_you_want_to_delete, item.name)) .positiveText(R.string.delete) .onPositive((dialog, which) -> { File fontDir = FontManager.getFontDir(item.name); File[] listFiles = fontDir.listFiles(); if (listFiles != null) { for (File file : listFiles) { file.delete(); } } fontDir.delete(); dls.removeEntry(getFontDownloadKey(item.name)); notifyDataSetChanged(); }) .negativeText(R.string.cancel) .show(); }; } @Override public void onStateChanged(DownloadService.DownloadEntry entry, DownloadService.State originalState) { adapter.notifyDataSetChanged(); if (originalState == DownloadService.State.finished) { String fontName = getFontNameFromDownloadKey(entry.key); if (fontName == null) { // this download doesn't belong to font manager. return; } try { String downloadedZip = getFontDownloadDestination(fontName); File fontDir = FontManager.getFontDir(fontName); fontDir.mkdirs(); Log.d(TAG, "Going to unzip " + downloadedZip, new Throwable().fillInStackTrace()); try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(downloadedZip)))) { ZipEntry ze; while ((ze = zis.getNextEntry()) != null) { String zname = ze.getName(); Log.d(TAG, "Extracting from zip: " + zname); File extractFile = new File(fontDir, zname); try (FileOutputStream fos = new FileOutputStream(extractFile)) { byte[] buf = new byte[4096]; int count; while ((count = zis.read(buf)) != -1) { fos.write(buf, 0, count); } } } } new File(downloadedZip).delete(); } catch (Exception e) { new MaterialDialog.Builder(FontManagerActivity.this) .content(getString(R.string.fm_error_when_extracting_font, fontName, e.getClass().getSimpleName() + ' ' + e.getMessage())) .positiveText(R.string.ok) .show(); } } } @Override public void onProgress(DownloadService.DownloadEntry entry, DownloadService.State originalState) { adapter.notifyDataSetChanged(); } }