JavascriptProva

lunedì 22 agosto 2016

Timidi approcci in Firebase...

Per vie traverse che riassumerò dopo, sono arrivato ad avere una giusta connessione (spero) con Firebase.
Sono adesso alla creazione di un riferimento per il database.
Ecco il sito dal quale sto cercando di farmi guidare ora...

Sto mettendo insieme un codice così:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FirebaseDatabase mDatabase=FirebaseDatabase.getInstance();
        


    }
E adesso mi si dice di avere un riferimento.
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FirebaseDatabase mDatabase=FirebaseDatabase.getInstance();
        DatabaseReference reference=mDatabase.getReference();


    }


Che riferimento è reference?

Sarebbe un riferimento a tutto il database.
Facciamo una prova...

Poi mi sono andato a perdere fra eventi e tremila cazzi... Ho trovato ora questa pagina che mi sembra più "umana"... vediamo...

Eccone la sintassi, simile a quella di cui sopra:
private DatabaseReference mDatabase;
// ...
mDatabase = FirebaseDatabase.getInstance().getReference();
Sarebbe un riferimento a tutto il database, suppongo.
A differenza di prima, dove creo separatamente un oggetto FirebaseDatabase mediante il metodo getInstance() e poi un oggetto DatabaseReference mediante il getReference(), li creo tutti insieme.
Seguo questo stesso esempio nel mio codice:
public class MainActivity extends AppCompatActivity {

    TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView=(TextView)findViewById(R.id.textView);
        
        DatabaseReference mDatabase= FirebaseDatabase.getInstance().getReference();




Finalmente ci sono riuscito.
La procedura è piuttosto complessa, per cui sarà meglio ripeterla con un nuovo progetto e una nuova App.
Ho un nuovo progetto, MioProgetto, su Firebase.
Ho difficoltà nel mettere al posto giusto il file scaricato.
Mi annoto la segnalazione del messaggio di errore:
Error:Execution failed for task ':app:processDebugGoogleServices'.
> File google-services.json is missing. The Google Services Plugin cannot function without it. 
   Searched Location: 
  C:\Users\Antonello\AndroidStudioProjects\StudioNuovo2\app\src\debug\google-services.json
  C:\Users\Antonello\AndroidStudioProjects\StudioNuovo2\app\google-services.json
Mi è bastato posizionare in App mediante Esplora Risorse.



Dunque, facciamo una distinzione.
  1. associamo una App ottenendo il numero Sha mediante la finestra Gradle sulla destra
  2. posizioniamo il file scaricato nella cartella App mediante Esplora Risorse
  3. sistemiamo i Gradle e facciamo il Sync
  4. nel Manifest, impostare il permesso Internet.
Dovrebbe bastare...

sabato 20 agosto 2016

Connessione di app android con database JSON Firebase.

Un nome "Studio Nuovo" sarà al di fuori di ogni sospetto...

Bene.
La radice di tutto, su Esplora Risorse, è la sottodirectory di "Android Studio Projects" chiamata "Studio Nuovo".
App è una sottocartella di questa.
Ecco: sono andato con il DOS e ho ricavato la struttura.
 Il volume nell'unit… C Š Acer
 Numero di serie del volume: E27D-F746

 Directory di C:\Users\Antonello\AndroidStudioProjects\StudioNuovo

20/08/2016  21.57    <DIR>          .
20/08/2016  21.57    <DIR>          ..
20/08/2016  21.48    <DIR>          .gradle
20/08/2016  21.53    <DIR>          .idea
20/08/2016  21.49    <DIR>          app
20/08/2016  21.48    <DIR>          build
20/08/2016  21.46    <DIR>          gradle
20/08/2016  21.46               105 .gitignore
20/08/2016  21.46               521 build.gradle
20/08/2016  21.46               872 gradle.properties
20/08/2016  21.46             4.971 gradlew
20/08/2016  21.46             2.404 gradlew.bat
20/08/2016  21.57                 0 lista.txt
20/08/2016  21.46               470 local.properties
20/08/2016  21.46                16 settings.gradle
20/08/2016  21.48               942 StudioNuovo.iml
               9 File         10.301 byte
               7 Directory  172.789.342.208 byte disponibili 
Andando più giù nella cartella App:
C:\Users\Antonello\AndroidStudioProjects\StudioNuovo\app>dir/p/o
 Il volume nell'unità C è Acer
 Numero di serie del volume: E27D-F746

 Directory di C:\Users\Antonello\AndroidStudioProjects\StudioNuovo\app

20/08/2016  21.49    <DIR>          .
20/08/2016  21.49    <DIR>          ..
20/08/2016  21.48    <DIR>          build
20/08/2016  21.46    <DIR>          libs
20/08/2016  21.46    <DIR>          src
20/08/2016  21.46                 8 .gitignore
20/08/2016  21.49             8.922 app.iml
20/08/2016  21.46               660 build.gradle
20/08/2016  21.46               700 proguard-rules.pro
               4 File         10.290 byte
               5 Directory  172.781.301.760 byte disponibili 
Ora vediamo come appare in Android Studio:



Ecco, quindi App, che qui viene mostrata isolata, è "compagna" delle cartelle che appaiono più sotto, ossia .idea, build, gradle: tutte "figlie" della cartella StudioNuovo.
Manca la cartella .gradle...
Comunque abbiamo due sedi in cui appaia questo ancora misterioso nome.
  1. Come file all'interno di App
  2. Come file "fratello" di App
Vediamo quale di questi due presenta quei requisiti.


Intanto devo rimontare il tutto con questo nuovo progetto.
Cancello i vari files scaricati in Download così evito quel numeretto fra parentesi...

Cancello tutti i progetti su Firebase e ne ricreo uno di sana pianta.

Vado alla console.
Associo al progetto JaccaProgetto il mio nuovo package, mi appare quella schermata ma me ne appare un'altra:



Prima probabilmente avevo saltato e non l'avevo vista.

Riprocediamo a salvare il file, che mi è stato già automaticamente scaricato, nella cartella App.
Eccolo, e senza numeretti.
Ora mi trovo al punto di prima


Cerchiamo il file gradle...eccetera che ha quella parola buildscript.
Bene. Si tratta del file "fratello" di App.
Eccolo:
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
Dunque devo trasformarlo in questo senso:
buildscript {
    // ...
    dependencies {
        // ...
        classpath 'com.google.gms:google-services:3.0.0'
    }
}
Ecco:nonostante il "don't place"...
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
        classpath 'com.google.gms:google-services:3.0.0'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}


Quindi questo:
apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "24.0.0"

    defaultConfig {
        applicationId "com.example.antonello.studionuovo"
        minSdkVersion 18
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
}
...va modificato in questo senso:
apply plugin: 'com.android.application'

android {
  // ...
}

dependencies {
  //apply plugin: 'com.android.application'

android {
  // ...
}

dependencies {
  // ...
  compile 'com.google.firebase:firebase-core:9.4.0'
}

// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services' ...
  compile 'com.google.firebase:firebase-core:9.4.0'
}

// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services'
E quindi:
apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "24.0.0"

    defaultConfig {
        applicationId "com.example.antonello.studionuovo"
        minSdkVersion 18
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.google.firebase:firebase-core:9.4.0'
}

apply plugin: 'com.google.gms.google-services'


A questo punto dovrebbe essere pronto, anche se non so cosa farne...

Lo faccio girare... giusto per vedere che non ci siano errori.

Ecco, non mi riconosceva una libreria. Ho fatto un lungo update di SDK e alla fine è partito! E questo già è consolante!

Tentativo di modifica di build.gradle e perplessità sulla struttura del progetto.

Veniamo al Gradle, grosso mistero, ancora, per me.
Il Tutorial dice che adesso bisogna aggiungere le regole al livello radice build.gradle
Ho risalvato nella cartella App il file google-services, senza il numeretto fra parentesi, per paura che non mi venisse riconosciuto il nome (lo avevo già scaricato in miei precedenti tentativi).

Troviamo il build.gradle.
Qui in App ce n'è un file solo, che si chiama così.
Vado a leggerlo:
apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "24.0.0"

    defaultConfig {
        applicationId "com.example.antonello.studiofirebase2"
        minSdkVersion 18
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
}


Il codice che bisogna modificare viene invece presentato così:
buildscript {
    // ...
    dependencies {
        // ...
        classpath 'com.google.gms:google-services:3.0.0'
    }
}
Quel buildscript non lo vedo da nessuna parte...

Un file che contiene buildscript si trova invece in StudioFirebase2.
Che faccio, modifico questo?
Ma in questa struttura dei progetti android non ci ho capito niente...
Non è che magari ci sono problemi col fatto che il nome di questo progetto è simile a quello di un progetto fatto prima?...

Costruisco da capo un progetto con un nome che non c'entra niente e cerco di capire qualcosa sulla sua struttura.

Connettere il database con l'app

Come si collega un'applicazione Android con il database?

Ho trovato un tutorial piuttosto datato che però potrebbe essere utile...

Andiamo a vedere il codice che dal sito moderno si dice di dover copiare. Intanto, come requisiti quali si pongono?
L'unico che mi sembra di non avere è Google Play Services 9.4.0 o più recente.
Che roba è?

Vado su SDK manager.
Trovo Google Play services 23.0.0, con un update available.
Installiamolo... non dovrebbe prendere troppo tempo.

In Android Studio viene chiuso l'IDE quando si fanno questi aggiornamenti...

Fatto.
Vado avanti.
Aggiungi Firebase alla tua App.
Come si fa?

Per aggiungere Firebase alla tua App hai bisogno di un progetto (e ce l'ho) e di un file di configurazione Firebase per la tua App. Ed è questo che presenta problemi...

Ora, il progetto (se si intende un database-storage eccetera) io ce l'ho già.
E allora dovrei cliccare su Import Google project.
Vediamo dove...

Creo un nuovo progetto per la confusione che ho combinato col primo.

Ma no, è giusto: devo cliccare sul simbolo verde: Add Firebase to Android App.
e Immagino di dover aggiungere Firebase all'applicazione che ho "di qua".
E devo inserire il nome del package.
Bene, l'ho fatto, ho digitato ADD APP, e mi è comparso un riquadro e contemporaneamente mi si è downloadato un file.
Il riquadro è questo:




E dice che lo devo copiare nella cartella App dell'applicazione.
Procedo subito.
Credo di averlo fatto decentemente...

Veniamo ora ad Add the SDK... Questo è il riferimento

Primissimi approcci con JSON su Firebase

Creo un progetto in Firebase.
Trovo scritto: "Un progetto è il tuo contenitore per Apps". Dunque non si tratta di un'App.
Vediamo di che si tratta, allora: sarà un insieme di progetti?

Ecco il primo form:



Ho aggiunto il nome di fantasia di un "progetto", ora inserisco la nazione corretta e vado...

Ottengo una pagina con questo elenco:



Ecco, a me interessa in particolare il database, quindi andiamo a vedere se se ne può fare qualcosa...

Intanto, ecco un link che dovrebbe indirizzare al mio database, forse... Ci sono dati personali in mezzo, per cui ritengo sia l'indirizzo di qualcosa di mio personale.



Ma mi rendo conto che la finestra principale della pagina presenta tre schede: DATA, RULES e USAGE.
Vado sulla pagina linkata da LEARN MORE, e scopro che bisogna innanzitutto definire le REGOLE. Andiamo su RULES e vediamo...

Apprendo che le regole sono scritte in una sintassi JavaScript-like.
Ecco la prima regola, che dovrebbe avere a che fare con l'accesso autorizzato dell'utente a dati privati:
{
  "rules": {
    ".read": "auth != null",
    ".write": "auth != null"
  }
}
Non conosco questi comandi.
Si dovrebbe approfondire...

Vado a vedere su altri eventuali tutorial...

Mi pare di aver capito che questo linguaggio si chiami JSON.

Voglio archiviare sul database una piccola stronzata.
Come faccio?

Questa cosa mi sembra promettente.

Il mio "indirizzo" è:
https://jacproject-c5cfa.firebaseio.com/
L'esempio riportato sul tutorial opera sull'indirizzo:
https://docs-examples.firebaseio.com/web/data
E' necessario aggiungere web/data?
Va aggiunto nell'albero?...



Per cominciare, cerchiamo di espandere questo database.

Se ho capito bene, la radice è quella, https://jacproject-c5cfa.firebaseio.com/
Provo questo approccio: tento di lavorare con json partendo dal javascript dove mi sento più a mio agio...

Ho trovato questo codice da aggiungere al codice HTML (credo):

<script src="https://www.gstatic.com/firebasejs/3.3.0/firebase.js"></script>
<script>
  // Initialize Firebase
  var config = {
    apiKey: "AIzaSyDAplxRFl1HcMMo5QYqt8RropQCx6no3Ok",
    authDomain: "jacproject-c5cfa.firebaseapp.com",
    databaseURL: "https://jacproject-c5cfa.firebaseio.com",
    storageBucket: "jacproject-c5cfa.appspot.com",
  };
  firebase.initializeApp(config);
</script>
Non succede letteralmente un tubo.
AH... mi rimanda a un link per usare il database... andiamo a vedere...

Sono ancora in fase indeterminata.
Come faccio ad aggiungere altri "campi"?

Ho sfondato! Decrittato il sistema!
Sulla scheda DATA della pagina relativa al database, posso aggiungere dei nodi al mio database in modo immediato, con una funzione che prima mi era sfuggita.

Ora vediamo che dati si possono inserire in JSON.

sabato 13 agosto 2016

Movimento di un oggetto nell'ambito di una activity.

Per il posizionamento dell'immagine nella finestra: voglio vedere se in WindowManager.LayoutParams vi sono indicazioni per il posizionamento preciso in base a un sistema di coordinate.
Ho già provato con setX() e non funziona.
E se provassi con setRawX()?
Proviamo...

Non esiste proprio. Devo fare una ricerca su WindowManager.LayoutParams. Ecco, ho trovato: esistono le proprietà param.x e param.y, nelle quali però la x esprime il posizionamento relativo a quello in cui l'oggetto viene posizionato inizialmente.
        Immagine immagine=new Immagine(this);

        WindowManager wm=(WindowManager)getSystemService(WINDOW_SERVICE);
                WindowManager.LayoutParams params=new WindowManager.LayoutParams(
                200,
                200,
                WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                        WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
                PixelFormat.TRANSPARENT);
        params.x=100;
        wm.addView(immagine, params);
(sempre in onCreate).
L'oggetto appare spostato di 100 rispetto al centro dove è stato caricato inizialmente.
Se è così, allora conviene metterlo in alto a sinistra, così il posizionamento relativo dovrebbe diventare assoluto facilitando il compito.

Ho fatto un po' di prove, e tutto è ok.

Ora provo a buttare giù qualcosa che lo sposti.


Con gli strumenti classici non mi sembra possibile spostare un oggetto posizionato direttamente sullo schermo.
Ma prima, a scopo formativo, è bene che mi ristudi un sistema per muovere oggetti entro un'activity.

Come funzionava quello per scrollare un'immagine entro una ImageView?
Ripasso!


Innanzitutto creo una classe:
public class Immagine extends ImageView {

    Context context;
    public Immagine(Context context) {
        super(context);
        this.context=context;
    }
}
Ora voglio metterci un'immagine da risorse.
Prendo un'immagine e la copio nelle risorse, come facevo per Eclipse.

Fatto!

Ora devo inserirla nella mia classe che eredita ImageView.
public class Immagine extends ImageView {

    Context context;
    public Immagine(Context context) {
        super(context);
        this.context=context;
        
        setImageResource(R.drawable.pupazzo);
    }
}
Devo istanziare un oggetto di questa classe, ovviamente...
In MainActivity:
public class MainActivity extends AppCompatActivity {

    RelativeLayout mainLayout;
    Immagine immagine;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mainLayout=(RelativeLayout)findViewById(R.id.mainLayout);
        immagine=new Immagine(this);
        mainLayout.addView(immagine);
        
    }

}
(meglio istanziare oggetti dichiarandone le variabili come variabili di istanza anziché come variabili di metodo, locali) E vediamo il risultato...

Bene, ho ottenuto un'immagine molto grande.
Come fare per ridimensionarla?
public class MainActivity extends AppCompatActivity {

    RelativeLayout mainLayout;
    Immagine immagine;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mainLayout=(RelativeLayout)findViewById(R.id.mainLayout);
        immagine=new Immagine(this);

        mainLayout.addView(immagine);
        immagine.getLayoutParams().width=100;

    }

}
Se metto quest'ultima riga prima dell'aggiunta dell'immagine a mainLayout ottengo un errore NullPointerException perché l'immagine non esiste ancora non essendo ancora stata aggiunta).


Per demarcare l'immagine dal resto, coloro l'activity principale in modo diverso dal bianco.

Bene, sono riuscito alla fine a posizionare l'immagine, non senza qualche problemino dovuto al fatto che non ricordo lo ScaleType da impostare all'immagine.
Alla fine il codice è questo:
public class MainActivity extends AppCompatActivity {

    RelativeLayout mainLayout;
    Immagine immagine;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mainLayout=(RelativeLayout)findViewById(R.id.mainLayout);
        immagine=new Immagine(this);
        immagine.setScaleType(ImageView.ScaleType.FIT_START);
        immagine.setY(0);
        mainLayout.addView(immagine);
        immagine.getLayoutParams().width=200;
        immagine.getLayoutParams().height=200;

    }

}
Per il momento tralascio quel FIT_START, agirò su di esso solo se ci saranno problemi per quanto riguarda lo scrolling.

Ora voglio iniziare, non ricordando bene i codici, dalle cose più semplici: imposto la cosa in modo tale che al semplice tocco la coordinata X cambi.

        immagine.setOnTouchListener(new View.OnTouchListener(){

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                v.setX(100);
                return true;
            }
        });
E riesce perfettamente.
Dunque, facciamo che al movimento i valori attuali di X e Y (tipo float) vengano immagazzinati in due variabili, dopo aver calcolato lo spostamento in rapporto ai valori precedenti delle due variabili.
La prima variabile va impostata all'azione DOWN anziché MOVE.


Sì, ho realizzato lo spostamento, ma non c'è correlazione fra lo spostamento della figura e lo spostamento del mio dito.
Forse il RelativeLayout non fornisce, con il setX e il setY, le giuste coordinate.
Infatti ho ritrovato un mio vecchio codice in cui usavo parametri derivati dal RelativeLayout, e li prendevo a ogni getAction dell'evento Touch.
Provo a rifare adesso la stessa cosa...

Ecco, ho ristudiato il mio vecchio codice.
Il principio è che
  1. Il punto di contatto viene preso una volta sola.
  2. All'azione DOWN viene rilevata la distanza fra il punto di contatto e il margine dell'oggetto.
  3. All'azione MOVE l'oggetto viene riposizionato in base alla distanza del margine dal punto di contatto.
public class MainActivity extends AppCompatActivity {

    float deltaX,deltaY;
    float X,Y;
    RelativeLayout mainLayout;
    Immagine immagine;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mainLayout=(RelativeLayout)findViewById(R.id.mainLayout);
        immagine=new Immagine(this);
        immagine.setScaleType(ImageView.ScaleType.FIT_START);
        RelativeLayout.LayoutParams rl=new RelativeLayout.LayoutParams(0,0);
        mainLayout.addView(immagine,rl);
        immagine.getLayoutParams().width=200;
        immagine.getLayoutParams().height=200;


        immagine.setOnTouchListener(new View.OnTouchListener(){

            public boolean onTouch(View v, MotionEvent event) {

                X=event.getRawX();
                Y=event.getRawY();

                switch(event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) v.getLayoutParams();
                        deltaX = X - lp.leftMargin;
                        deltaY = Y - lp.topMargin;
                        break;

                    case MotionEvent.ACTION_MOVE:
                        lp = (RelativeLayout.LayoutParams) v.getLayoutParams();
                        lp.leftMargin = (int) (X - deltaX);
                        lp.topMargin = (int) (Y - deltaY);
                        v.setLayoutParams(lp);
                        break;
                }

                return true;
            }
        });
    }



}

venerdì 12 agosto 2016

Aggiunta di azione al bottone isolato

Ora dovrei aggiungere un'azione a quella immagine che ho creato sovrapposta allo schermo.
Ho trovato il modo modificando in tal modo il codice:
        WindowManager wm=(WindowManager)getSystemService(WINDOW_SERVICE);
                WindowManager.LayoutParams params=new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
                0,
                PixelFormat.TRANSLUCENT);
        params.gravity= Gravity.RIGHT | Gravity.TOP;
altrimenti l'azione non parte.
L'azione è come evento TouchEvent nel codice della View:
public class Immagine extends View {
    Paint paint;
    Context context;
    public Immagine(Context context) {
        super(context);
        this.context=context;
        paint=new Paint();
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(5);
        paint.setColor(Color.RED);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event){
        Uri ringtoneUri= RingtoneManager.getActualDefaultRingtoneUri(context,RingtoneManager.TYPE_RINGTONE);
        Ringtone ringtone=RingtoneManager.getRingtone(context,ringtoneUri);
        ringtone.play();
        return true;
    }


    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        canvas.drawCircle(100, 100, 50, paint);
    }.


}
Il toast non ha una durata illimitata. Ciò è strano.

Ci ho messo altre gestioni dell'evento come il cambiamento di colore dell'activity, e, come qui, una suoneria.

Adesso dovrei esercitarmi a creare un pulsante libero e dargli una funzione.

Però voglio creare un Service di quelli "stabili". Il codice non lo ricordo per niente...