package dk.dr.radio.akt; import android.annotation.TargetApi; import android.content.Intent; import android.graphics.Rect; import android.media.AudioManager; import android.os.Build; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.TouchDelegate; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.DecelerateInterpolator; import android.view.animation.ScaleAnimation; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.SeekBar; import android.widget.TextView; import com.androidquery.AQuery; import dk.dr.radio.afspilning.Afspiller; import dk.dr.radio.afspilning.Status; import dk.dr.radio.afspilning.wrapper.AndroidMediaPlayerWrapper; import dk.dr.radio.afspilning.wrapper.Wrapperfabrikering; import dk.dr.radio.data.DRData; import dk.dr.radio.data.DRJson; import dk.dr.radio.data.Kanal; import dk.dr.radio.data.Lydkilde; import dk.dr.radio.data.Udsendelse; import dk.dr.radio.diverse.AnimationAdapter; import dk.dr.radio.diverse.App; import dk.dr.radio.diverse.Log; import dk.dr.radio.diverse.Sidevisning; import dk.dr.radio.v3.R; public class Afspiller_frag extends Basisfragment implements Runnable, View.OnClickListener, SeekBar.OnSeekBarChangeListener { private AQuery aq; private ImageView startStopKnap; private ProgressBar progressbar; private ImageView kanallogo; private TextView direktetekst; private TextView metainformation; private ImageView udvidSkjulKnap; private View udvidSkjulOmråde; private View rod; private View indhold_overskygge; Lydstyrke lydstyrke = new Lydstyrke(); private boolean seekBarBetjenesAktivt; private TextView starttid; private TextView slutttid; private SeekBar seekBar; Runnable opdaterSeekBar = new Runnable() { @Override public void run() { App.forgrundstråd.removeCallbacks(this); try { Afspiller afspiller = DRData.instans.afspiller; if (afspiller.getAfspillerstatus()!=Status.STOPPET && viserUdvidetOmråde()) App.forgrundstråd.postDelayed(this, 1000); /* boolean denneUdsSpiller = udsendelse.equals(afspiller.getLydkilde()) && afspiller.getAfspillerstatus() != Status.STOPPET; if (!denneUdsSpiller || App.accessibilityManager.isEnabled()) { return; } */ Udsendelse u = DRData.instans.afspiller.getLydkilde().getUdsendelse(); //long passeret = App.serverCurrentTimeMillis() - u.startTid.getTime(); //long længde = u.slutTid.getTime() - u.startTid.getTime(); //int passeretPct = længde > 0 ? (int) (passeret * 100 / længde) : 0; //Log.d(u + " passeretPct=" + passeretPct + " af længde=" + længde); //seekBar.setProgress((int) passeret); if (!seekBarBetjenesAktivt) { // Kun hvis vi ikke er i gang med at søge i udsendelsen if (afspiller.getLydkilde().erDirekte()) { if (u!=null && u.startTid!=null && u.slutTid!=null) { seekBar.setVisibility(View.VISIBLE); seekBar.setEnabled(false); starttid.setVisibility(View.VISIBLE); slutttid.setVisibility(View.VISIBLE); int længdeMs = (int) (u.slutTid.getTime() - u.startTid.getTime()); seekBar.setMax(længdeMs); starttid.setText(u.startTidKl); slutttid.setText(u.slutTidKl); seekBar.setProgress((int) (App.serverCurrentTimeMillis() - u.startTid.getTime())); } else { seekBar.setVisibility(View.VISIBLE); seekBar.setEnabled(false); starttid.setVisibility(View.VISIBLE); slutttid.setVisibility(View.VISIBLE); } } else { seekBar.setVisibility(View.VISIBLE); seekBar.setEnabled(true); starttid.setVisibility(View.VISIBLE); slutttid.setVisibility(View.VISIBLE); int længdeMs = (int) afspiller.getDuration(); if (længdeMs>0) seekBar.setMax(længdeMs); slutttid.setText(DateUtils.formatElapsedTime(længdeMs / 1000)); int pos = (int) afspiller.getCurrentPosition(); Log.d(" pos " + pos + " " + længdeMs); if (pos > 0) { // pos=0 rapporteres efter onSeekComplete, det skal ignoreres starttid.setText(DateUtils.formatElapsedTime(pos / 1000)); seekBar.setProgress(pos); } } } } catch (Exception e) { Log.rapporterFejl(e); } } }; @Override public void onProgressChanged(SeekBar seekBarx, int progress, boolean fromUser) { if (fromUser) { DRData.instans.afspiller.seekTo(progress); starttid.setText(DateUtils.formatElapsedTime(progress / 1000)); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { seekBarBetjenesAktivt = true; //seekBarTekst.setVisibility(View.VISIBLE); App.forgrundstråd.removeCallbacks(opdaterSeekBar); } @Override public void onStopTrackingTouch(SeekBar seekBar) { seekBarBetjenesAktivt = false; //seekBarTekst.setVisibility(View.INVISIBLE); App.forgrundstråd.postDelayed(opdaterSeekBar, 1000); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d("Viser fragment " + this); rod = inflater.inflate(R.layout.afspiller_frag, container, false); aq = new AQuery(rod); starttid = aq.id(R.id.starttid).typeface(App.skrift_gibson).getTextView(); slutttid = aq.id(R.id.slutttid).typeface(App.skrift_gibson).getTextView(); seekBar = aq.id(R.id.seekBar).getSeekBar(); seekBar.setOnSeekBarChangeListener(this); rod.setOnClickListener(this); // Fang klik på baggrunden, så de ikke går til det underliggende lag startStopKnap = aq.id(R.id.startStopKnap).clicked(this).getImageView(); udvidSkjulKnap = aq.id(R.id.udvidSkjulKnap).getImageView(); // udvid/skjul knap - hvis vi bruger en onClickListener får vi først besked når knappen slippes. // I stedet viser/skjuler vi allerede når fingeren trykkes ned på viewet udvidSkjulKnap.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { udvidSkjulOmråde(); } return false; } }); udvidSkjulOmråde = aq.id(R.id.udvidSkjulOmråde).gone().getView(); progressbar = aq.id(R.id.progressBar).getProgressBar(); kanallogo = aq.id(R.id.kanallogo).clicked(this).typeface(App.skrift_gibson).getImageView(); direktetekst = aq.id(R.id.direktetekst).clicked(this).typeface(App.skrift_gibson).getTextView(); metainformation = aq.id(R.id.metainformation).clicked(this).typeface(App.skrift_gibson_fed).getTextView(); // Knappen er meget vigtig, og har derfor et udvidet område hvor det også er den man rammer // se http://developer.android.com/reference/android/view/TouchDelegate.html final int udvid = getResources().getDimensionPixelSize(R.dimen.hørknap_udvidet_klikområde); startStopKnap.post(new Runnable() { @Override public void run() { Rect r = new Rect(); startStopKnap.getHitRect(r); r.top -= udvid; r.bottom += udvid; r.right += udvid; r.left -= udvid; //Log.d("hør_udvidet_klikområde=" + r); ((View) startStopKnap.getParent()).setTouchDelegate(new TouchDelegate(r, startStopKnap)); } }); aq.id(R.id.forrige).clicked(this); aq.id(R.id.næste).clicked(this); DRData.instans.afspiller.observatører.add(this); DRData.instans.afspiller.forbindelseobservatører.add(this); DRData.instans.afspiller.positionsobservatører.add(this); lydstyrke.init(aq.id(R.id.lydstyrke).getSeekBar()); run(); // opdatér views if (App.accessibilityManager.isEnabled()) setHasOptionsMenu(true); return rod; } @Override public void onDestroyView() { DRData.instans.afspiller.observatører.remove(this); DRData.instans.afspiller.forbindelseobservatører.remove(this); DRData.instans.afspiller.positionsobservatører.remove(this); super.onDestroyView(); } int startStopKnapImageResource; int startStopKnapNyImageResource; @Override public void run() { App.forgrundstråd.postDelayed(opdaterSeekBar, 1000); Lydkilde lydkilde = DRData.instans.afspiller.getLydkilde(); Kanal kanal = lydkilde.getKanal(); if (kanal == null) { Log.rapporterFejl(new IllegalStateException("kanal er null for "+lydkilde+ " "+lydkilde.getClass())); return; } Udsendelse udsendelse = lydkilde.getUdsendelse(); kanallogo.setImageResource(kanal.kanallogo_resid); direktetekst.setVisibility(lydkilde.erDirekte()?View.VISIBLE:View.GONE); metainformation.setText(udsendelse!=null?udsendelse.titel:kanal.navn); switch (DRData.instans.afspiller.getAfspillerstatus()) { case STOPPET: startStopKnapNyImageResource = R.drawable.afspiller_spil; startStopKnap.setContentDescription(getString(R.string.Start_afspilning)); progressbar.setVisibility(View.GONE); break; case FORBINDER: startStopKnapNyImageResource = R.drawable.afspiller_pause; startStopKnap.setContentDescription(getString(R.string.Stop_afspilning)); progressbar.setVisibility(View.VISIBLE); int fpct = DRData.instans.afspiller.getForbinderProcent(); metainformation.setText(getString(R.string.Forbinder) + (fpct > 0 ? " "+fpct : "")); break; case SPILLER: startStopKnapNyImageResource = R.drawable.afspiller_pause; startStopKnap.setContentDescription(getString(R.string.Stop_afspilning)); progressbar.setVisibility(View.GONE); break; } if (startStopKnapImageResource == 0) { startStopKnap.setImageResource(startStopKnapNyImageResource); } else if (startStopKnapImageResource != startStopKnapNyImageResource) { Animation anim; anim = new ScaleAnimation(1, 1.2f, 1, 1.2f, startStopKnap.getWidth() / 2, startStopKnap.getHeight() / 2); anim.setDuration(100); anim.setRepeatCount(1); // skalér ind og ud igen anim.setRepeatMode(Animation.REVERSE); anim.setInterpolator(new DecelerateInterpolator()); anim.setAnimationListener(new AnimationAdapter() { @Override public void onAnimationRepeat(Animation animation) { startStopKnap.setImageResource(startStopKnapNyImageResource); } }); startStopKnap.startAnimation(anim); } startStopKnapImageResource = startStopKnapNyImageResource; if (App.accessibilityManager.isEnabled() && getActivity() != null) ActivityCompat.invalidateOptionsMenu(getActivity()); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { if (App.accessibilityManager.isEnabled()) try { inflater.inflate(R.menu.tilg_afspiller, menu); MenuItem menuItem = menu.findItem(R.id.startStopKnap); if (DRData.instans.afspiller.getAfspillerstatus() == Status.STOPPET) { menuItem.setTitle(getString(R.string.Start) + DRData.instans.afspiller.getLydkilde().getNavn()); } else { menuItem.setTitle(R.string.Stop_afspilning); menuItem.setIcon(R.drawable.dri_radio_stop_graa40); } } catch (Exception e) { Log.rapporterFejl(e); } // fix for https://mint.splunk.com/dashboard/project/cd78aa05/errors/4021328508 super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.startStopKnap) { if (DRData.instans.afspiller.afspillerstatus == Status.STOPPET) { DRData.instans.afspiller.startAfspilning(); } else { DRData.instans.afspiller.stopAfspilning(); } } return super.onOptionsItemSelected(item); } public boolean viserUdvidetOmråde() { return udvidSkjulOmråde.getVisibility() == View.VISIBLE; } /* Virkede med android:animateLayoutChanges="true" public void udvidSkjulOmråde() { final View indhold_overskygge = getActivity().findViewById(R.id.indhold_overskygge); if (viserUdvidetOmråde()) { udvidSkjulOmråde.setVisibility(View.GONE); udvidSkjulKnap.setImageResource(R.drawable.dri_pil_op_graa40); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { indhold_overskygge.animate().alpha(0).withEndAction(new Runnable() { @Override public void run() { // Får det til at hakke midt i animationen // TODO fix, ved at lave egen åbne/lukke animation i afspiller, der ikke først fader og DEREFTER krympler området //indhold_overskygge.setVisibility(View.GONE); } }); } else { indhold_overskygge.setVisibility(View.GONE); } } else { udvidSkjulOmråde.setVisibility(View.VISIBLE); udvidSkjulKnap.setImageResource(R.drawable.dri_pil_ned_graa40); indhold_overskygge.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { udvidSkjulOmråde(); // Skjul udvidet afspiller igen indhold_overskygge.setOnTouchListener(null); return true; } }); indhold_overskygge.setVisibility(View.VISIBLE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { indhold_overskygge.animate().alpha(1); } } } */ public void setIndholdOverskygge(View v) { indhold_overskygge = v; indhold_overskygge.setVisibility(View.GONE); } View.OnTouchListener indhold_overskygge_onTouchListener = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { udvidSkjulOmråde(); // Skjul udvidet afspiller igen return true; } }; public void udvidSkjulOmråde() { if (!viserUdvidetOmråde()) { Sidevisning.vist(Afspiller_frag.class); indhold_overskygge.setOnTouchListener(indhold_overskygge_onTouchListener); int forrigeNæsteSynlighed = DRData.instans.afspiller.getLydkilde().erDirekte() ? View.GONE : View.VISIBLE; aq.id(R.id.forrige).visibility(forrigeNæsteSynlighed).id(R.id.næste).visibility(forrigeNæsteSynlighed); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { indhold_overskygge.setVisibility(View.VISIBLE); udvidSkjulOmråde.setVisibility(View.VISIBLE); int højde = udvidSkjulOmråde.getHeight(); //App.kortToast("højde " + højde); int højdeGæt = getResources().getDimensionPixelSize(R.dimen.afspiller_udvidet_højde_gæt); if (højde == 0) { //udvidSkjulKnap.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); højde = højdeGæt; //App.kortToast("højde "+højde); } else { if (højdeGæt != højde) { Log.d("udvidSkjulOmråde(): højdeGæt på " + højdeGæt + " afviger fra reel højde på " + højde); } } rod.setTranslationY(højde); rod.animate().translationY(0); indhold_overskygge.animate().alpha(1); udvidSkjulKnap.animate().rotation(-180); } else { udvidSkjulKnap.setImageResource(R.drawable.dri_pil_ned_graa40); indhold_overskygge.setVisibility(View.VISIBLE); udvidSkjulOmråde.setVisibility(View.VISIBLE); } opdaterSeekBar.run(); // skal ske efter at udvidSkjulOmråde er sat til synligt lydstyrke.run(); } else { App.forgrundstråd.removeCallbacks(opdaterSeekBar); App.forgrundstråd.removeCallbacks(lydstyrke); indhold_overskygge.setOnTouchListener(null); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { rod.animate().translationY(udvidSkjulOmråde.getHeight()); indhold_overskygge.animate().alpha(0).withEndAction(new Runnable() { @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override public void run() { indhold_overskygge.setVisibility(View.GONE); udvidSkjulOmråde.setVisibility(View.GONE); rod.setTranslationY(0); } }); udvidSkjulKnap.animate().rotation(0); } else { udvidSkjulKnap.setImageResource(R.drawable.dri_pil_op_graa40); udvidSkjulOmråde.setVisibility(View.GONE); indhold_overskygge.setVisibility(View.GONE); } } } @Override public void onClick(View v) { if (v == startStopKnap) { if (DRData.instans.afspiller.afspillerstatus == Status.STOPPET) { DRData.instans.afspiller.startAfspilning(); } else { DRData.instans.afspiller.stopAfspilning(); } } else if (v.getId() == R.id.forrige) { DRData.instans.afspiller.forrige(); } else if (v.getId() == R.id.næste) { DRData.instans.afspiller.næste(); } else if (v== kanallogo || v==direktetekst || v==metainformation) try { // Ved klik på baggrunden skal kanalforside eller aktuel udsendelsesside vises Lydkilde lydkilde = DRData.instans.afspiller.getLydkilde(); FragmentManager fm = getFragmentManager(); if (lydkilde.erDirekte()) { // Fjern backstak - så vi starter forfra i 'roden' fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); // Vis kanaler (den aktuelle getKanal vælges automatisk af Kanaler_frag) fm.beginTransaction() .replace(R.id.indhold_frag, new Kanaler_frag()) .commit(); Sidevisning.vist(Kanaler_frag.class); } else { Udsendelse udsendelse = lydkilde.getUdsendelse(); Fragment f = Fragmentfabrikering.udsendelse(udsendelse); f.getArguments().putString(P_kode, lydkilde.getKanal().kode); getActivity().getSupportFragmentManager().beginTransaction() .replace(R.id.indhold_frag, f) .addToBackStack(null) .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) .commit(); Sidevisning.vist(f.getClass(), udsendelse.slug); } } catch (Exception e) { Log.rapporterFejl(e); } // Fix for https://www.bugsense.com/dashboard/project/cd78aa05/errors/825688064 } class Lydstyrke implements Runnable, SeekBar.OnSeekBarChangeListener { public SeekBar seekBar; public int opdateringshastighed = 1000; public void init(SeekBar seekBar) { this.seekBar = seekBar; seekBar.setMax(App.audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)); seekBar.setOnSeekBarChangeListener(this); run(); } @Override public void run() { int nu = App.audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); seekBar.setProgress(nu); Log.d("Lydstyrke "+nu); App.forgrundstråd.removeCallbacks(this); if (!viserUdvidetOmråde()) return; App.forgrundstråd.postDelayed(this, opdateringshastighed); // opdater 1 gang i sekundet } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (!fromUser) return; App.audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, progress, AudioManager.FLAG_SHOW_UI); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } } }