Java tutorial
/** Esperanto-radio por Androjd, farita de Jacob Nordfalk. Kelkaj partoj de la kodo originas de DR Radio 2 por Android, vidu http://code.google.com/p/dr-radio-android/ Esperanto-radio por Androjd estas libera softvaro: vi povas redistribui ?in kaj/a modifi ?in kiel oni anoncas en la licenco GNU enerala Publika Licenco (GPL) versio 2. Esperanto-radio por Androjd estas distribuita en la espero ke ?i estos utila, sed SEN AJNA GARANTIO; sen e la implica garantio de surmerkatigindeco a tageco por iu aparta celo. Vidu la GNU enerala Publika Licenco por pli da detaloj. Vi devus ricevi kopion de la GNU enerala Publika Licenco kune kun la programo. Se ne, vidu <http://www.gnu.org/licenses/>. */ package dk.dr.radio.data; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.widget.Toast; import dk.dr.radio.afspilning.Ludado; import dk.nordfalk.esperanto.radio.App; import dk.nordfalk.esperanto.radio.R; import java.io.IOException; import java.util.HashMap; import org.json.JSONException; /** * Det centrale objekt som alt andet bruger til */ public class DRData { public static final int efdatumojID=8; private static final String LOSILO_EFDATUMOJ = "esperantoradio_kanaloj_v" + efdatumojID; private static final String kanalojUrl = "http://javabog.dk/privat/" + LOSILO_EFDATUMOJ + ".json"; private static final String LOSILO_ELSENDOJ = "elsendoj"; public static final boolean evoluiganto = false; public HashMap<String, Bitmap> emblemoj = new HashMap<String, Bitmap>(); public Ludado ludado; public Handler handler = new Handler(); public boolean udsendelser_ikkeTilgngeligt; public static DRData instanco; public String rektaElsendaPriskribo; public Grundata efdatumoj; public String aktualaKanalkodo; public Kanal aktualaKanalo; public Udsendelse aktualaElsendo; public static final String LOSILO_kanalo = "kanalo"; /** Bruges til at sende broadcasts om nye stamdata */ public static final String INTENT_novaj_efdatumoj="dk.dr.radio.afspiller.OPDATERING_Stamdata"; /** Bruges til at sende broadcasts om ny info om udsendelsen (programinfo) */ public static final String INTENT_novaj_elsendoj = "dk.dr.radio.afspiller.OPDATERING_Udsendelse"; /** Bruges til at sende broadcasts om ny info om hvad der spiller nu */ public static final String OPDATERINGSINTENT_SpillerNuListe = "dk.dr.radio.afspiller.OPDATERING_SpillerNuListe"; /** Hvis true er indlsning i gang og der skal vises en venteskrm. * Man kan vente p et broadcast eller kalde wait() for at blive vkket nr indlsning er frdig */ public boolean indlserVentVenligst=false; // // Opdateringer i baggrunden. // private boolean baggrundsopdateringAktiv = false; private boolean baggrundstrdSkalVente = true; public static void ?ar?iInstancon() throws IOException, JSONException, PackageManager.NameNotFoundException { long komenco = System.currentTimeMillis(); if (evoluiganto) Toast.makeText(App.app, "Programo fre?e startita", Toast.LENGTH_LONG).show(); //if (evoluiganto) Debug.startMethodTracing("/data/data/dk.nordfalk.esperanto.radio/files/trace.data"); int efdatumojResId = App.app.getResources().getIdentifier(LOSILO_EFDATUMOJ, "raw", App.app.getPackageName()); if (efdatumojResId == 0) throw new InternalError("Ne trovita: " + LOSILO_EFDATUMOJ); String efdatumojJson = App.prefs.getString(LOSILO_EFDATUMOJ, null); String elsendojStr = App.prefs.getString(LOSILO_ELSENDOJ, null); if (efdatumojJson == null) { // Indls fra raw this vi ikke har nogle cachede stamdata i prefs //InputStream is = akt.getResources().openRawResource(R.raw.stamdata_android22); efdatumojJson = FilCache.lsInputStreamSomStreng(App.app.getResources().openRawResource(efdatumojResId)); } if (elsendojStr == null) { // Indls fra raw this vi ikke har nogle cachede stamdata i prefs //InputStream is = akt.getResources().openRawResource(R.raw.stamdata_android22); elsendojStr = FilCache.lsInputStreamSomStreng(App.app.getResources().openRawResource(R.raw.radio)); } Log.d((System.currentTimeMillis() - komenco) + " akiris datumojn "); instanco = new DRData(); instanco.efdatumoj = new Grundata(efdatumojJson); instanco.efdatumoj.leguElsendojn(elsendojStr); Log.d((System.currentTimeMillis() - komenco) + " parsis datumojn "); instanco.?ar?iKanalEmblemojn(true); Log.d((System.currentTimeMillis() - komenco) + " ?ar?is kanalbildojn "); // Daras tro da tempo! Ne faru en la efa fadeno! Log.d(instanco.efdatumoj.kanaler); // Kanalvalg. Tjek frst Preferences, brug derefter JSON-filens forvalgte kanal // Por nun 'Muzaiko' estu cxiam la antauxelektita kanalo //if (instans.aktualaKanalkodo == null) instans.aktualaKanalkodo = prefs.getString(LOSILO_kanalo, null); if (instanco.aktualaKanalkodo == null) instanco.aktualaKanalkodo = instanco.efdatumoj.json.optString("komenca_kanalo"); instanco.stKanalOgUdsendelseSikkert(instanco.aktualaKanalkodo); instanco.ludado = new Ludado(); instanco.ludado.setKanalon(instanco.aktualaKanalo.navn, instanco.aktualaElsendo.sonoUrl); //if (evoluiganto) Debug.stopMethodTracing(); Log.d((System.currentTimeMillis() - komenco) + " finis ?argadon"); // 31. okt: Fjernet af Jacob - da baggrundstrden ikke skal startes af f.eks. widgetter // se kontroluFonaFadenoStartis() //if (!instans.fonaFadeno.isAlive()) instans.fonaFadeno.start(); } /** * Frst efter indlstning starter vi baggrundstrden - fra splash og fra afspiller_akt. * Dette er et separat skridt da det ikke skal ske ved opstart af levende ikon */ public void kontroluFonaFadenoStartis() { if (!fonaFadeno.isAlive()) fonaFadeno.start(); } public void ?an?iKanalon(String novaKanalkodo) { Log.d("DRData.skiftKanal(" + novaKanalkodo); stKanalOgUdsendelseSikkert(novaKanalkodo); App.prefs.edit().putString(LOSILO_kanalo, aktualaKanalkodo).commit(); rektaElsendaPriskribo = null; // Vk baggrundstrden s den indlser den nye kanals elsendo etc og laver broadcasts med nyt info baggrundstrdSkalOpdatereNu(); } private void stKanalOgUdsendelseSikkert(String kodo) { aktualaKanalkodo = kodo; aktualaKanalo = efdatumoj.kanalFraKode.get(aktualaKanalkodo); if (aktualaKanalo == null || aktualaKanalo.udsendelser.size() == 0) { // Ne devus okazi, sed tamen okazas se oni neniam ajn elektis kanalon aktualaKanalo = efdatumoj.kanaler.get(0); aktualaKanalkodo = aktualaKanalo.kode; } // iam elektu la plej lastan elsendon aktualaElsendo = aktualaKanalo.udsendelser.get(aktualaKanalo.udsendelser.size() - 1); } public void setBaggrundsopdateringAktiv(boolean aktiv) { if (baggrundsopdateringAktiv == aktiv) return; baggrundsopdateringAktiv = aktiv; Log.d("setBaggrundsopdateringAktiv( " + aktiv); if (baggrundsopdateringAktiv) baggrundstrdSkalOpdatereNu(); // vk baggrundtrd } private void baggrundstrdSkalOpdatereNu() { baggrundstrdSkalVente = false; synchronized (fonaFadeno) { fonaFadeno.notify(); } } final Thread fonaFadeno = new Thread() { @Override public void run() { ?ar?iKanalEmblemojn(false); efdatumoj.?ar?iElsendojnDeRss(false); efdatumoj.forprenuMalplenajnKanalojn(); App.app.sendBroadcast(new Intent(INTENT_novaj_efdatumoj)); // Hovedlkke while (true) { try { if (baggrundstrdSkalVente) synchronized (fonaFadeno) { if (baggrundsopdateringAktiv) fonaFadeno.wait(15000); // Vent 15 sekunder. Men vgn op hvis nogen kalder fonaFadeno.notify()! // baggrundsopdateringAktiv kan vre sat til false inden for de sidste 15 sekunder og s skal vi vente videre if (!baggrundsopdateringAktiv) fonaFadeno.wait(); // Vent indtil trden vkkes fonaFadeno.wait(50); // Vent kort s den aktiverende trd kan gre sit arbejde frdigt } baggrundstrdSkalVente = true; hentUdsendelserOgSpillerNuListe(); App.tracker.dispatch(); } catch (Exception ex) { Log.e(ex); } } } }; { fonaFadeno.setPriority((Thread.MIN_PRIORITY + Thread.NORM_PRIORITY) / 2); } // malalta prioritato private void hentUdsendelserOgSpillerNuListe() { Log.d("hentUdsendelserOgSpillerNuListe(" + aktualaKanalkodo); if (aktualaElsendo.rektaElsendaPriskriboUrl != null) try { // Muzaiko rektaElsendaPriskribo = FilCache.hentUrlSomStreng(aktualaElsendo.rektaElsendaPriskriboUrl); if (rektaElsendaPriskribo.toLowerCase().contains("<html>")) { // La rektaElsendaPriskriboUrl ne devus enhavi <html>-kodojn. Se gxi havas, tiam // versxajne estas iu 'hotspot' kiu kaptis la adreson kaj kiu // sendas ensalutan pagxon rektaElsendaPriskribo = "Ne povis el?uti"; } App.app.sendBroadcast(new Intent(INTENT_novaj_elsendoj)); } catch (Exception ex) { Log.e(ex); rektaElsendaPriskribo = "Ne povis el?uti"; } else { rektaElsendaPriskribo = null; } // Tjek om en evt ny udgave af stamdata skal indlses final String STAMDATA_SIDST_INDLST = "stamdata_sidst_indlst"; long sidst = App.prefs.getLong(STAMDATA_SIDST_INDLST, 0); long nu = System.currentTimeMillis(); long alder = (nu - sidst) / 1000 / 60; if (alder >= 30) try { // stamdata er ldre end en halv time Log.d("Stamdata er " + alder + " minutter gamle, opdaterer dem..."); // Opdater tid (hvad enten indlsning lykkes eller ej) App.prefs.edit().putLong(STAMDATA_SIDST_INDLST, nu).commit(); String efdatumoj2Str = FilCache.hentUrlSomStreng(kanalojUrl); final Grundata efdatumoj2 = new Grundata(efdatumoj2Str); // Hentning og parsning gik godt - vi gemmer den nye udgave i prefs App.prefs.edit().putString(LOSILO_EFDATUMOJ, efdatumoj2Str).commit(); try { String elsendojStr = FilCache.hentUrlSomStreng(efdatumoj2.elsendojUrl); efdatumoj2.leguElsendojn(elsendojStr); // Hentning og parsning gik godt - vi gemmer den nye udgave i prefs App.prefs.edit().putString(LOSILO_ELSENDOJ, elsendojStr).commit(); } catch (Exception e) { Log.e("Fejl parsning af " + efdatumoj2.elsendojUrl, e); } efdatumoj2.?ar?iElsendojnDeRss(false); efdatumoj2.forprenuMalplenajnKanalojn(); Log.d(instanco.efdatumoj.kanaler); handler.post(new Runnable() { public void run() { efdatumoj = efdatumoj2; App.app.sendBroadcast(new Intent(INTENT_novaj_efdatumoj)); } }); ?ar?iKanalEmblemojn(false); } catch (Exception e) { Log.e("Fejl parsning af stamdata. Url=" + kanalojUrl, e); } } private boolean ?ar?iKanalEmblemojn(boolean nurLokajn) { boolean ioEstisSxargxita = false; for (Kanal k : efdatumoj.kanaler) { if (k.eo_emblemoUrl != null && emblemoj.get(k.eo_emblemoUrl) == null) try { String dosiero = FilCache.akiriDosieron(k.eo_emblemoUrl, true, nurLokajn); if (dosiero == null) continue; /* int kiomDaDpAlta = 50; // 50 dp // Convert the dps to pixels final float scale = appCtx.getResources().getDisplayMetrics().density; int alteco = (int) (kiomDaDpAlta * scale + 0.5f); Bitmap res = kreuBitmapTiomAlta(dosiero, alteco); */ Bitmap res = BitmapFactory.decodeFile(dosiero); if (res != null) ioEstisSxargxita = true; emblemoj.put(k.eo_emblemoUrl, res); } catch (Exception ex) { Log.e(ex); } } return ioEstisSxargxita; } /* private static Bitmap kreuBitmapTiomAlta(String dosiero, int alteco) { Options options = new BitmapFactory.Options(); options.inScaled = false; options.inDither = false; options.inJustDecodeBounds = true; BitmapFactory.decodeFile(dosiero, options); int desiredH = 50; int srcWidth = options.outWidth; int srcHeight = options.outHeight; // Only scale if the source is big enough. This code is just trying to fit a image into a certain width. if (desiredH > srcHeight) { desiredH = srcHeight; } // Calculate the correct inSampleSize/scale value. This helps reduce memory use. It should be a power of 2 // from: http://stackoverflow.com/questions/477572/android-strange-out-of-memory-issue/823966#823966 int inSampleSize = 1; while (srcHeight / 2 > desiredH) { srcHeight /= 2; srcHeight /= 2; inSampleSize *= 2; } //float desiredScale = (float) desiredH / srcHeight; options.inJustDecodeBounds = false; options.inDither = false; options.inSampleSize = inSampleSize; options.inScaled = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; Bitmap res = BitmapFactory.decodeFile(dosiero, options); return res; } */ /* malnova - forigu public String findKanalUrlFraKode(Kanalo kanal) { String url = kanal.rektaElsendaSonoUrl; if (aktualaElsendo != null && aktualaElsendo.sonoUrl!=null) { url = aktualaElsendo.sonoUrl; } String info = "Kanal: "+kanal.nomo+"\n"+url; if (Datumoj.evoluiganto) Toast.makeText(appCtx, info, Toast.LENGTH_LONG).show(); Log.d(info); return url; } */ public void kundividi(Activity akt) { Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_SUBJECT, "Esperanto-radio por Androjd"); sendIntent.putExtra(Intent.EXTRA_TEXT, "Saluton!\n\n" + "Mi rekomendas ke vi elprovas tiun i programon per via Androjda telefono:\n" + "La Esperanto-radio de Muzaiko\n" + "https://market.android.com/details?id=dk.nordfalk.esperanto.radio\n" + "\n" + "Muzaiko estas Esperanto-radio kiu konstante elsendas.\n" + "Eblas anka askulti la lastatempajn elsendojn de deko da aliaj radistacioj." // +"\n\n(kaj... ne forgesu meti 5 stelojn :-)" ); sendIntent.setType("text/plain"); akt.startActivity(Intent.createChooser(sendIntent, "Sendi al")); } }