JavascriptProva

mercoledì 27 luglio 2016

Sistemazione delle SeekBars per gli intervalli fra le segnalazioni.

Con qualche "colpo di copia-incolla" ho tolto il codice XML che rappresentava le SeekBars dall'attività principale e lo ho messe su una nuova attività chiamata TimeSettings.
Dato che le shapes sono già nella cartella drawables vengono recepite anche qui, e così le due bars mi vengono già ben formattate da un punto di vista estetico.

Ho impostato il massimo a 240 minuti (4 ore)
Ora, per rendere la scala graduata a 10 minuti, devo fare, come già fatto prima nell'altra mia prova, la divisione intera del valore della barra per 10, e poi moltiplicare per 10.
Ecco:
public class TimeSettings extends Activity {

 SeekBar seekBarMin, seekBarMax;
 TextView textViewMin,textViewMax;
 int intero;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_time_settings);
  seekBarMin=(SeekBar)findViewById(R.id.seekBar1);
  seekBarMax=(SeekBar)findViewById(R.id.seekBar2);
  textViewMin=(TextView)findViewById(R.id.textView1);
  textViewMax=(TextView)findViewById(R.id.textView2);
  
  seekBarMin.setMax(240);  //4 ore * 60 minuti
  seekBarMin.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
   
   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    intero=10*(progress/10);
    textViewMin.setText(""+intero);
    
   }
  });
 }


}
E funziona: sulla TextBarMin appaiono i minuti, in cambiamenti discreti di 10 minuti per volta.

Ora devo commutare in ore e minuti, tremite un altro calcolo matematico: divisione intera per 60 e modulo 60.
   @Override
   public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    intero=10*(progress/10);
    int ore=intero/60;
    int minuti=intero%60;
    textViewMin.setText(ore+" ORE : "+minuti+" MINUTI");
E verifichiamo...

Funziona.

Una finezza: se si tratta di 1 ora, appare scritto "ORA" e non "ORE". Più "umano" e attraente:
   @Override
   public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    intero=10*(progress/10);
    int ore=intero/60;
    int minuti=intero%60;
    String strOra="ORE";
    if(ore==1)strOra="ORA";
    textViewMin.setText(ore+" "+strOra+" E "+minuti+" MINUTI");
    
   }
Okay.


Ho sistemato le due SeekBars, con una serie di finezze che rendono il testo molto "human friendly":
  seekBarMin.setMax(240);  //4 ore * 60 minuti
  seekBarMin.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
   
   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    int intero=10*(progress/10);
    int ore=intero/60;
    int minuti=intero%60;
    
    String stringaDelleOre;
    String stringaDeiMinuti;
    String stringaEt="";
    
    if(ore==0){
     stringaDelleOre="";
    }
    else if(ore==1){
     stringaDelleOre=ore+" ORA "; 
    }
    else{
     stringaDelleOre=ore+" ORE ";     
    }    
    if(minuti==0){
     stringaDeiMinuti="";     
    }
    else if(minuti==1){
     stringaDeiMinuti=minuti+" MINUTO ";          
    }
    else{
     stringaDeiMinuti=minuti+" MINUTI ";
    }    
    if(ore!=0 && minuti!=0) stringaEt=" E ";
    if(ore==0 && minuti==0) {
     stringaDelleOre=ore+" ORE";
     stringaEt= " E ";
     stringaDeiMinuti=minuti+" MINUTI";
    }

    textViewMin.setText(stringaDelleOre+stringaEt+stringaDeiMinuti);
    
    if(progress>seekBarMax.getProgress())seekBarMax.setProgress(progress);
   }
  });
  
  seekBarMax.setMax(240);
  seekBarMax.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
   
   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    int intero=10*(progress/10);
    int ore=intero/60;
    int minuti=intero%60;
    
    String stringaDelleOre;
    String stringaDeiMinuti;
    String stringaEt="";
    
    if(ore==0){
     stringaDelleOre="";
    }
    else if(ore==1){
     stringaDelleOre=ore+" ORA "; 
    }
    else{
     stringaDelleOre=ore+" ORE ";     
    }    
    if(minuti==0){
     stringaDeiMinuti="";     
    }
    else if(minuti==1){
     stringaDeiMinuti=minuti+" MINUTO ";          
    }
    else{
     stringaDeiMinuti=minuti+" MINUTI ";
    }    
    if(ore!=0 && minuti!=0) stringaEt=" E ";
    if(ore==0 && minuti==0) {
     stringaDelleOre=ore+" ORE";
     stringaEt= " E ";
     stringaDeiMinuti=minuti+" MINUTI";
    }

    textViewMax.setText(stringaDelleOre+stringaEt+stringaDeiMinuti);
    if(progress<seekBarMin.getProgress())seekBarMin.setProgress(progress);
   }
  });
 }

Ripasso dei menu per rimaneggiamento dell'interfaccia di FFD

Ora dobbiamo aggiungere i settings.
Devo far entrare in causa le SeekBars.
Sono un po' indeciso se mettere le SeekBars su un'altra activity per evitare che possano essere manomesse distrattamente, e anche per orientare le SeekBars in modalità Landscape consentendo una più fine regolazione dei tempi.
Mi sembra il caso.
Per farlo, devo creare un menu che apra l'attività Impostazioni.
Un'occasione per ripassare i Menu.


Ci sono due eventi, per la gestione dei Menu. Uno è la creazione del Menu e l'altro è la selezione del Menu.

Quindi il primo è onCreateOptionsMenu. Come faccio per ricordare il nome? Ricordando che si tratta di un Menu di opzioni.
Ha come parametro un oggetto menu di tipo Menu.
Quindi chiama la funzione getMenuInflater, che ha come parametro un menu già presente nella cartella menu (o che si può anche creare) che lo inflata e credo inizializzi la variabile menu ad esso.
Restituisce un valore booleano, quindi il metodo è booleano.
Provo a scriverlo.
 @Override
 public boolean onCreateOptionsMenu(Menu menu){
  getMenuInflater().inflate(R.menu.prova, menu);
  return true;
 }
Questa dovrebbe creare il menu. Vediamo quale ne è l'effetto scrivendola su un'attività della mia app...

Mi appaiono i tre puntini, e cliccandoci sopra mi appare un menu con scritto "Settings".
Vediamo la struttura xml del menu contenuto nella cartella...

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.example.ffd.MainActivity" >

    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:showAsAction="never"
        android:title="@string/action_settings"/>

</menu> 
La scritta "Settings" deve provenire dal file string, contenuto nella cartella values.
Vediamolo...

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">FFD</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
    <string name="title_activity_form">Form</string>
    <string name="title_activity_prova">Prova</string>

</resources> 
Ecco: la scritta di nome action_settings reca "Settings".
Provo a cambiarla con "Impostazioni" scritto in maiuscolo per vedere se cambia.

PERFETTO!

Ora tolgo questo metodo per vedere se mi spariscono i tre puntini...
Ecco, sì, spariscono.
E se invece faccio dare al metodo un risultato false?
 @Override
 public boolean onCreateOptionsMenu(Menu menu){
  getMenuInflater().inflate(R.menu.main, menu);
  return false;
 }
Ecco, se restituisce false è come se non ci fosse: i tre puntini spariscono.

Ora vediamo il secondo metodo, quello che intercetta la selezione del menu.
Questa volta il centro di tutto non è il Menu ma l'elemento del Menu, ossia l'Item.
Quindi se quello di prima era un OptionsMenu, questo è un OptionsItem.
E quindi il nome del metodo è onOptionsItemSelected. Come parametro abbiamo MenuItem, ossia l'elemento del Menu.
Lo scopo è determinare quale MenuItem è stato selezionato, per cui se ne deve ricavare l'identità, ossia l'Id.
Poi si seleziona: a seconda di quale id corrisponda all'id del MenuItem selezionato si determina la conseguenza e segue la restituzione di true, altrimenti la funzione non termina e si restituisce super.onOptionsItemSelected con item per parametro.
La funzione che restituisce l'id del MenuItem selezionato è getItemId().
Quindi si confronta questo id con l'id del MenuItem scritto nel file xml.

Provo a cancellare e riscrivere...

Okay, sembra che ci sia riuscito piuttosto bene.

Ora scrivo nella mia App anche questa, insieme alla prima.
 @Override
 public boolean onCreateOptionsMenu(Menu menu){
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }
 
 @Override
 public boolean onOptionsItemSelected(MenuItem item){
  int id=item.getItemId();
  if(id==R.id.action_settings){
   Log.d("Menu selezionato", ""+item.getTitle());
   return true;
  }
  return super.onOptionsItemSelected(item);
 }
Vediamo se mi viene scritto in LogCat il nome del MenuItem.

Perfetto!
07-27 13:13:49.361: D/Menu selezionato(25304): IMPOSTAZIONI

Correzione dell'errore dovuto alla non istanziazione dell'interfaccia listener da parte di Form.

Ed ecco che mi si ripresenta l'errore quando torno dal Form al Service.
Credo di aver capito, con gli impazzimenti di ieri, che l'errore sia dovuto al fatto che soltanto il Main istanzia la variabile che ospita l'interfaccia nel Service.
Riprovo a eseguire...

Ecco: quando viene terminato Main, nel momento in cui ritorno a StartTime nel TimerService, ottengo un messaggio di errore con questo LogCat:
07-27 10:25:51.360: E/AndroidRuntime(31345): java.lang.NullPointerException
07-27 10:25:51.360: E/AndroidRuntime(31345):  at com.example.ffd.TimerService.StartTime(TimerService.java:54)
Ed ecco che il NullPointerException credo sia dovuto al fatto che non ho chiamato il setter da Form, per cui:
  1. Quando termino Main, TimerService termina;
  2. L'alarm mi evoca Form al momento stabilito, ma stavolta non viene evocato nessun setter che istanzi la variabile interfaccia;
  3. Quando deve essere innescato l'evento della variabile interfaccia di Service, questo non esiste.
Pongo allora la condizione di innescare l'evento soltanto se questo esiste, in StartTime e in StopTime:

TimerService:
if(mAlarmChangeListener!=null) mAlarmChangeListener.AlarmChange();
E vediamo...

Funziona egregiamente!

martedì 26 luglio 2016

Inserimento nell'applicazione del CustomEventListener sullo stato di AlarmManager

Ora si inserisce il CustomEvent.
Per cominciare, creo un'interfaccia in TimerService:
 public interface OnAlarmChangeListener{
  public void AlarmChange();
 }
Quindi creo una variabile in TimerService, di tipo OnAlarmChangeListener:
public class TimerService extends Service {

 IBinder mBinder=new LocalBinder();
 
 OnAlarmChangeListener mAlarmChangeListener;
 
 @Override
 public IBinder onBind(Intent intent) {
  // TODO Auto-generated method stub
  return mBinder;
 }

......
e quindi nel corpo di TimerService creo il setter:
 public void setOnAlarmChangeListener(OnAlarmChangeListener onAlarmChangeListener){
  mAlarmChangeListener= onAlarmChangeListener;
 }
Questo dovrebbe consentirmi di inserire in Main il codice del setter: lo inserisco appena realizzata la connessione.

Main:
  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   LocalBinder bnd=(LocalBinder)service;
   mService=bnd.getService();
   mBound=true;
   mService.setOnAlarmChangeListener(new OnAlarmChangeListener(){

    @Override
    public void AlarmChange() {
     Log.d("ALARM", "CHANGED");
     
    }
    
   });
   
  }
E vediamo se mi dà il giusto segnale...

Niente... ma io, nel corpo di TimerService, non ho dato da nessuna parte l'ordine di innescare l'evento AlarmChange()...
Lo faccio:
 public void StartTime(){
  Intent intent=new Intent(getApplicationContext(),
        Form.class);
  PendingIntent pendingIntent=PendingIntent.getActivity(getApplicationContext(), 
                0,
                intent, 
                0);
  AlarmManager alarmManager=(AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
  alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 
      SystemClock.elapsedRealtime()+5*1000, 
      pendingIntent);
  mAlarmChangeListener.AlarmChange();
 }
 
 public void StopTime(){
  Intent intent=new Intent(getApplicationContext(),
    Form.class);
  PendingIntent pendingIntent=PendingIntent.getActivity(getApplicationContext(), 
            0,
            intent, 
            0);
  AlarmManager alarmManager=(AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
  alarmManager.cancel(pendingIntent);
  if(pendingIntent!=null)pendingIntent.cancel();
  mAlarmChangeListener.AlarmChange();
 }
...e rivediamo.

Funziona!
Ecco il LogCat:
07-27 06:26:55.876: D/ALARM(15540): CHANGED
07-27 06:27:00.711: D/ALARM(15540): CHANGED
07-27 06:27:02.332: D/ALARM(15540): CHANGED
07-27 06:27:03.994: D/ALARM(15540): CHANGED
Bene.
Adesso posso manovrare la mia piccola View chiamata "semaforo" che cambia colore a seconda del fatto che alarmManager sia settato o no.
Creo la variabile oggetto e la inizializzo:
 View semaforo;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  Log.d("MAIN", "ONCREATE");
  
  semaforo=(View)findViewById(R.id.semaforo);
E aggiusto il codice del setter:
  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   LocalBinder bnd=(LocalBinder)service;
   mService=bnd.getService();
   mBound=true;
   mService.setOnAlarmChangeListener(new OnAlarmChangeListener(){

    @Override
    public void AlarmChange() {
     if(mService.AlarmOn()){
      semaforo.setBackgroundResource(R.drawable.tondinoverde);
     }else{
      semaforo.setBackgroundResource(R.drawable.tondinorosso);
     }
     
    }
    
   });
E vediamo...

Perfetto!
Aggiusto anche la disabilitazione dei pulsanti "Attiva" e "Disattiva".
  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   LocalBinder bnd=(LocalBinder)service;
   mService=bnd.getService();
   mBound=true;
   mService.setOnAlarmChangeListener(new OnAlarmChangeListener(){

    @Override
    public void AlarmChange() {
     if(mService.AlarmOn()){
      semaforo.setBackgroundResource(R.drawable.tondinoverde);
      bttStart.setEnabled(false);
      bttStop.setEnabled(true);
     }else{
      semaforo.setBackgroundResource(R.drawable.tondinorosso);
      bttStart.setEnabled(true);
      bttStop.setEnabled(false);
     }
     
    }
    
   });
Proviamo...

Funziona, ma quando si apre il programma, o quando si riapre l'attività Main dopo che era stata chiusa, non viene messo in atto nessun comportamento adeguato allo stato di Alarm.
Metto nel TimerService il codice per l'innesco dell'evento AlarmChange direttamente nel setter.

TimerService:
 public void setOnAlarmChangeListener(OnAlarmChangeListener onAlarmChangeListener){
  mAlarmChangeListener= onAlarmChangeListener;
  mAlarmChangeListener.AlarmChange();
 }
E proviamo...

Funziona egregiamente!

Impostazione del ciclo base fra due activities e un service (tecnica mia)

Riscrivo tutto il codice del mio sistema di interazione fra due Activities e un Service per generare intervalli di tempo casuali...

Ho già l'XML pronto per la precedente prova, che ho distrutto in seguito a un errore che mi ha fatto impazzire. L'XML lo riciclo.
Ho preparato un po' il codice di MainActivity:
public class MainActivity extends Activity {

 Button bttStart, bttStop, bttHide;
 SeekBar seekBarMin, seekBarMax;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  
 }

}
Ma per prima cosa mi conviene scrivere il Service chiamato TimerService, e bindarlo.
Scrivo il codice per bindarlo alle due attività:

TimerService:
class TimerService extends Service {

 IBinder mBinder=new LocalBinder();
 
 @Override
 public IBinder onBind(Intent intent) {
  // TODO Auto-generated method stub
  return mBinder;
 }
 
 public class LocalBinder extends Binder{
  TimerService getService(){
   return TimerService.this;
  }
 }
 
}


Ora bindo con MainActivity
public class MainActivity extends Activity {

 TimerService mService;
 boolean mBound;
 
 Button bttStart, bttStop, bttHide;
 SeekBar seekBarMin, seekBarMax;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  
 }
 
 @Override
 public void onStart(){
  super.onStart();
  Intent intent=new Intent(this,TimerService.class);
  bindService(intent,mConnection,Service.BIND_AUTO_CREATE);
 }
 
 @Override
 public void onStop(){
  super.onStop();
  if(mBound!=false){
   unbindService(mConnection);
   mBound=false;
  }
 }
 ServiceConnection mConnection=new ServiceConnection(){

  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   LocalBinder bnd=(LocalBinder)service;
   mService=bnd.getService();
   mBound=true;
   
  }

  @Override
  public void onServiceDisconnected(ComponentName name) {
   mBound=false;
   
  }
  
 };

}
Ecco, credo che ci sia tutto.
Passo a creare il binding anche con Form, l'altra activity:
public class Form extends Activity {

 TimerService mService;
 boolean mBound;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_form);
 }
 
 @Override
 public void onStart(){
  super.onStart();
  Intent intent=new Intent(this,TimerService.class);
  bindService(intent,mConnection,Service.BIND_AUTO_CREATE);
 }
 
 @Override
 public void onStop(){
  super.onStop();
  if(mBound!=false){
   unbindService(mConnection);
   mBound=false;
  }
 }

 ServiceConnection mConnection=new ServiceConnection(){

  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   LocalBinder bnd=(LocalBinder)service;
   mService=bnd.getService();
   mBound=true;
   
  }

  @Override
  public void onServiceDisconnected(ComponentName name) {
   mBound=false;
   
  }
  
 };


}
Ecco. Ora, però, vorrei testare il corretto funzionamento.
Inserisco dei "segnali" negli eventi onCreate e onDestroy.
 @Override
 public void onCreate(){
  super.onCreate();
  Log.d("TIMERSERVICE","ONCREATE");
 }
 
 @Override
 public void onDestroy(){
  super.onDestroy();
  Log.d("TIMERSERVICE", "ONDESTROY");
 }
Metto dei segnali anche nei codici delle attività:

Main:
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  Log.d("MAIN", "ONCREATE");
  
 }

..........

 @Override
 public void onDestroy(){
  super.onDestroy();
  Log.d("MAIN", "ONDESTROY");
 }


Form:
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_form);
  
  Log.d("FORM", "ONCREATE");
 }

........

 @Override
 public void onDestroy(){
  super.onDestroy();
  Log.d("FORM","ONDESTROY");
 }

Ora devo inserire il codice per gli intervalli di tempo in TimerService:
 public void StartTime(){
  Intent intent=new Intent(getApplicationContext(),
        Form.class);
  PendingIntent pendingIntent=PendingIntent.getActivity(getApplicationContext(), 
                0,
                intent, 
                0);
  AlarmManager alarmManager=(AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
  alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 
      SystemClock.elapsedRealtime()+5*1000, 
      pendingIntent);
 }
 
 public void StopTime(){
  Intent intent=new Intent(getApplicationContext(),
    Form.class);
  PendingIntent pendingIntent=PendingIntent.getActivity(getApplicationContext(), 
            0,
            intent, 
            0);
  AlarmManager alarmManager=(AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
  alarmManager.cancel(pendingIntent);
  if(pendingIntent!=null)pendingIntent.cancel();
 }
 
 boolean AlarmOn(){
  Intent intent=new Intent(getApplicationContext(),
    Form.class);
  boolean al=(PendingIntent.getActivity(getApplicationContext(),
            0,
            intent,
            PendingIntent.FLAG_NO_CREATE)!=null);
  return al;
         
 }
Ora scrivo il codice dei bottoni, e posiziono un bottone in Form, per muovermi fra attività e services.

Main:
  bttStart=(Button)findViewById(R.id.button1);
  
  bttStart.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    mService.StartTime();
    
   }
  });
  bttStop=(Button)findViewById(R.id.button2);
  
  bttStop.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    mService.StopTime();
    
   }
  });
 }


Form:
  button=(Button)findViewById(R.id.button1);
  button.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    mService.StartTime();
    
   }
  });
Credo sia pronto per la prova.
Registro il Service:
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <service android:name=".TimerService" />
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" > 
E vediamo...

Problemino iniziale: IllegalAccess: accesso alla classe TimerService non consentito.
Avevo dimenticato public:
public class TimerService extends Service {

 IBinder mBinder=new LocalBinder();
Semplice distrazione!
Corretto questo, il programma parte.

Secondo intoppo: da Form non torna indietro: ho dimenticato di mettere finish() nel codice del button di Form.
   @Override
   public void onClick(View v) {
    mService.StartTime();
    finish();
    
   }
Okay.
Funziona anche lo StopTime.

Ma adesso devo fare la prova relativa al problema che ieri mi ha fatto impazzire, terminando Main una volta che questo ha impostato alarmManager sul TimerService.
A tale scopo, metto un codice nel button che deve terminare il Main.
  bttHide=(Button)findViewById(R.id.bttHide);
  bttHide.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    finish();
    
   }
  });
E riproviamo...

Funziona anche questo!

OnUtteranceCompletedListener

Ho ripassato nuovamente il modo di intercettare la fine della sintesi vocale.
Già l'avevo visto in precedenza

Ecco il codice:
public class MainActivity extends Activity {

 TextToSpeech tts;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  tts=new TextToSpeech(this,new TextToSpeech.OnInitListener() {
   
   
   
   @Override
   public void onInit(int status) {
    if(status==TextToSpeech.SUCCESS){
     int result=tts.setLanguage(Locale.ITALIAN);
     OnUtteranceCompletedListener utteranceListener=new OnUtteranceCompletedListener(){

      @Override
      public void onUtteranceCompleted(String utteranceId) {
       Log.d("UTTERANCE", "COMPLETED");
       
      }
      
     };
     tts.setOnUtteranceCompletedListener(utteranceListener);
     HashMap hashMap=new HashMap();
     hashMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "qualcosa");
     

     tts.speak("Ciao, bellissimo",TextToSpeech.QUEUE_FLUSH,hashMap);
    }
    
   }
  });
 }


}
Salvo e rifaccio...

sabato 23 luglio 2016

Codice per gli intervalli minimo e massimo tramite SeekBar.

Codice definitivo per gli intervalli minimo e massimo:
public class MainActivity extends Activity {

 SeekBar seekBar1, seekBar2;
 TextView textView,textView2;
 int step;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  step=15;
  textView=(TextView)findViewById(R.id.textView1);
  textView2=(TextView)findViewById(R.id.textView2);
  
  seekBar1=(SeekBar)findViewById(R.id.seekBar1);
  seekBar2=(SeekBar)findViewById(R.id.seekBar2);
  
  seekBar1.setMax(60*4);
  seekBar2.setMax(60*4);
  
  

  textView.setText(0+" "+0);
  textView2.setText(0+" "+0);

  
  seekBar1.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
   
   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {
    
   }
   
   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    int numero=step*(progress/step);
    int ore=numero/60;
    int minuti=numero%60;
    textView.setText(ore+" "+minuti);
    if(progress>seekBar2.getProgress()) seekBar2.setProgress(progress);
   }
  });
  
  seekBar2.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
   
   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    int numero=step*(progress/step);
    int ore=numero/60;
    int minuti=numero%60;
    textView2.setText(ore+" "+minuti);
    if(progress<seekBar1.getProgress()) seekBar1.setProgress(progress);
    
   }
  });
 }

}