domenica 22 marzo 2020

Ubuntu Touch su Nexus 7 2 gen

Mi ero gia' occupato oramai molti anni fa del progetto Ubuntu Touch (all'epoca Ubuntu for phones) piu' che altro perche' lo sviluppo era legato a Qt.


Per installare Ubuntu Touch sui dispositivi supportati la soluzione piu' semplice e' utilizzare UBPorts Installer

Per avere la taskbar si deve fare swipe da sinistra a destra, per avere l'elenco delle applicazioni aperte swipe da sinistra a destra  (swipe lento cicla tra le app, swipe veloce fa vedere tutte le app aperte)

Swipe da destra



Swipe da sinistra


Lo screenshot corrisponde alla pressione contemporanea dei due tasti del volume

Le applicazioni si installano da OpenStore



La mancanza di software e' abbastanza devastante!!

Per disinstallare una app si preme a lungo l'icona, si aprira' una nuova finestra con l'opzione rimozione

Per abilitare la connessione SSH con il tablet si digita sul computer

ssh-keygen

poi si copiano le chiavi sul tablet

adb push ~/.ssh/id_rsa.pub /home/phablet/
sempre sul tablet si copiano le chiavi

mkdir /home/phablet/.ssh 
chmod 700 /home/phablet/.ssh 
cat /home/phablet/id_rsa.pub >> /home/phablet/.ssh/authorized_keys 
chmod 600 /home/phablet/.ssh/authorized_keys 
chown -R phablet.phablet /home/phablet/.ssh
sudo android-gadget-service enable ssh 

A questo punto per collegarsi via rete si prende l'ip del tablet e si entra in SSH

ssh phablet@ip_address


Per editare direttamente sul tablet via cavo USB si puo' usare semplicemente

adb shell

La password di root della shell e' il codice PIN

Si puo' effettuare un mirror dello schermo del tablet sul pc tramite il comando

adb exec-out timeout 120 mirscreencast -m /run/mir_socket --stdout --cap-interval 2 -s 384 640 | mplayer -demuxer rawvideo -rawvideo w=384:h=640:format=rgba -



Per programmare UBPorts non si usa piu' Ubuntu SDK ma si utilizza  Clickable

Per installare si procede  con il seguente codice

pip3 install git+https://gitlab.com/clickable/clickable.git

si deve poi mettere in Path la directory $HOME/.local/bin e si deve avere in Path anche Adb

 The scripts futurize and pasteurize are installed in '/home/luca/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  The script cookiecutter is installed in '/home/luca/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  The script jsonschema is installed in '/home/luca/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  The script clickable is installed in '/home/luca/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.

Sul tablet si devono abilitare i permessi da sviluppatore da Impsotazioni/Informazioni/Modalita' sviluppatore/  (ATTENZIONE: la modalita' sviluppatore non si puo' abilitare se non e' stato impostato un blocco schermo per esempio con Pin Code)

a questo punto per creare un progetto si usa

clickable create 

attenzione: per le voci AppName e Namespace non possono essere usati caratteri speciali (sono ammessi caratteri alfabetici ed il punto)

Per testare la applicazione si puo' digitare

clickable desktop

altrimenti con il solo clickable si effettua l'upload sul tablet

Applicazione Python in esecuzione su desktop
La stessa applicazione in esecuzione sul tablet

Come IDE si puo' usate l'editor Atom con il plugin https://atom.io/packages/atom-build-clickable
e selezionare la directory del progetto

Per compilare e lanciare la app sul tablet si preme F9. Se si preme F7 si puo' scegliere come target il desktop od il tablet.


attenzione : al momento di compilare il progetto viene effettuato il download di un docker con una immagine di Ubuntu 16.04 quindi c'e' necessita' di spazio disco e connessione di rete

Un libro di riferimento per la programmazione si trova a questo link

https://legacy.gitbook.com/book/mimecar/ubuntu-touch-programming-course/details

Database su Android con Room e Kotlin

Il nuovo approccio per avere un database persistente su Android e' quello di utilizzare Room

Per integrare la libreria nel progetto Android si deve modificare il file build.gradle (app) aggiungendo il plugin kapt in testa

apply plugin: 'com.android.application'apply plugin: 'kotlin-android'apply plugin: 'kotlin-android-extensions'apply plugin: 'kotlin-kapt'

ed aggiungendo le seguenti dipendenze (questo sono le dipendenze per Kotlin, nel caso di uso di Java la terza riga, quella che inizia con kapt, deve essere sostituita con
annotationProcessor "androidx.room:room-compiler:$room_version"
==============================
def room_version = "2.2.5"
implementation "androidx.room:room-runtime:$room_version"kapt "android.arch.persistence.room:compiler:$room_version"
// optional - Kotlin Extensions and Coroutines support for Roomimplementation "androidx.room:room-ktx:$room_version"
// Test helperstestImplementation "androidx.room:room-testing:$room_version"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0"

La gestione delle chiamate Rooms avviene per SQL

In sintesi viene definito il tracciato record del database. Da notare che non sono esplicitamente previsti campi DateTime; per questo motivo uso lo Unix Time come Long
Il nome dell'unica tabella e' nome_tabella

Le query sono incluse nella sezione DAO. Ogni query riporta un int che dice quante righe sono state interessate dalla query stessa

Nella sezione Database viene collegata la tabella al Db
Attenzione: se si cambia il tracciato record deve essere modificato il numero di versione del Db
Il nome del file e' inserito in DatabaseBuilder

Le query vengono gestite all'interno di coroutine

Per copiare il database dal telefono al PC si puo' usare

adb -d shell "run-as com.luca.innocenti.roomdb cat /data/data/com.luca.innocenti.roomdb/databases/sensori.db" > /home/luca/room.db

dove com.luca.innocenti.roomdb e' il nome del package mentre sensori.db e' il nome del file
database sul telefono
Altrimenti da Android Studio si va su View/Tool Windows/Device File Explorer

Per leggere il file su desktop si puo' utilizzare DB Browser for SQLite

package com.luca.innocenti.roomdb

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.room.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {

    @Entity(tableName = "nome_tabella")
    data class TabellaEntity(
            @PrimaryKey(autoGenerate = true)
            var id: Int,            @ColumnInfo(name = "tempo") var tempo: Long = 0,            @ColumnInfo(name = "pitch") var pitch: Float = 0.0f,            @ColumnInfo(name = "roll") var roll: Float = 0.0f,            @ColumnInfo(name = "azimuth") var azimuth: Float = 0.0f,            @ColumnInfo(name = "nota") var nota: String

    )

    @Dao    interface DbDao {
        @Query("SELECT * FROM nome_tabella")
        fun getAll(): List<TabellaEntity>

        @Query("SELECT * FROM nome_tabella WHERE nota LIKE :nota")
        fun findByNota(nota: String): List<TabellaEntity>

        @Insert        fun insertAll(vararg todo: TabellaEntity)

        @Delete        fun delete(todo: TabellaEntity)

        @Query("DELETE FROM nome_tabella WHERE id = :id")
        fun getSingleRecordDelete(id: Int): Int

        @Query("UPDATE nome_tabella SET nota=:nota WHERE id = :indice")
        fun getSingleRecordUpdate(nota: String, indice: Int): Int


        @Update        fun updateDb(vararg todos: TabellaEntity)
    }

    @Database(entities = [TabellaEntity::class], version = 1)
    abstract class AppDatabase : RoomDatabase() {
        abstract fun DbDao(): DbDao
    }


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)


        val db = Room.databaseBuilder(
                applicationContext,                AppDatabase::class.java, "sensori.db"        ).build()

        GlobalScope.launch {            db.DbDao().insertAll(TabellaEntity(0,12,13.4f,7.7f,0.3f,"Nota"))
            db.DbDao().insertAll(TabellaEntity(0,13,13.4f,7.7f,0.3f,"Nota2"))

            var data = db.DbDao().getAll()

            data?.forEach {                Log.d("test", it.toString())
            }
            var ricerca = db.DbDao().findByNota("Nota")
            ricerca?.forEach{                Log.d("ricerca", ricerca.toString())
            }
            db.DbDao().getSingleRecordDelete(6)

            data = db.DbDao().getAll()
            data?.forEach {                Log.d("dopo", it.toString())
            }
            db.DbDao().getSingleRecordUpdate("modifica",6)

            data = db.DbDao().getAll()

            data?.forEach {                Log.d("dopo", it.toString())
            }
            //db.clearAllTables()            db.close()
        }    }
}

sabato 21 marzo 2020

Lotta contro CUPS

Visto il periodo mi sono dovuto ricreare l'ufficio in casa, stampante compresa. Ho ritirato fuori quella gia' vista qui e sono iniziati i problemi. Mentre 4 anni fa la avevo installata senza troppi problemi adesso sulla mia Debian testing la stampante si ostina a andare in pausa appena avere ricevuto l'input

I log non sono di aiuto....sembra essere un problema nel passaggio tra Cups e Ghostview. Dopo un vano tentativo di fare un downgrade di Cups ho provato la strada di ricompilare tutto da sorgenti

Prima con apt-get remove ho disinstallato cups e poi compilato da sorgenti (ultima versione disponibile a questo indirizzo)

https://github.com/apple/cups/releases/tag/v2.3.1

Una volta riavviato il servizio

service cups start

ancora errori sul file di log ma questo volta era un problema legato a "Filter failed"

e' stato sufficiente montare questi pacchetti che la stampante ha ripreso vita

apt-get install cups-filters
apt-get install foomatic-db
apt-get install foomatic-db-gutenprint

giovedì 19 marzo 2020

p7m e Linux

In questi giorni di telelavoro forzato mi sono trovato a lavorare sul mio portatile personale Linux invece della postazione lavorativa Windows con alcuni problemi legati ad alcuni software. Uno dei problemi e' stato quello di gestire gli allegati della PEC che in ufficio erano gestiti da Dike




Ho trovato una comoda soluzione in ArubaSign. In pratica si scarica l'installer da qui, di decomprime,si cambiano i permessi al file install.bat (che non e' un batch DOS ma uno script Python). Dopo di cio' e' sufficiente trascinare il file p7m su Verify e  si puo' estrarre il documento

venerdì 13 marzo 2020

Imagemagick cache

cercando di fare una gif animata partendo da circa 500 jpg ad alta risoluzione mi sono imbattuto nell'errore cache resources exhausted che non avevo mai incrociato

La soluzione per ovviare all'esaurimento della cache (sia di memoria Ram che di disco) e' editare
il file /etc/ImageMagick-6/policy.xml modificando i valori sottostanti


  <policy domain="resource" name="memory" value="4GiB"/>
  <policy domain="resource" name="map" value="512MiB"/>
  <policy domain="resource" name="width" value="16KP"/>
  <policy domain="resource" name="height" value="16KP"/>

giovedì 12 marzo 2020

Accensione automatica da ricarica di telefoni Android

Per un nuovo progetto avevo bisogno di una funzione che trovo molto comoda su IPhone, ovvero l'avvio automatico da spento quando viene inserito il cavo USB collegato alla corrente, e che non avevo trovato su Android

Lo scopo poi e' quello di avviare in automatico una applicazione una volta terminato il boot


Frugando ho trovato che questa opzione e' facilmente disponibile nei Nexus con semplici comandi da fastboot

./adb reboot bootloader
./fastboot oem off-mode-charge 0
./fastboot reboot

A questo punto per rimuovere il lock screen di Android si va in Impostazioni/Sicurezza/Blocco schermo/nessuno

A questo punto sarebbe interessante avviare in automatico un app (od un servizio)
Per fare una prova ho usato Nexus 5 con Android 6 perche' le versioni piu' recenti
di Android rendono piu' difficile lanciare una app al boot in automatico

Si vede modificare il Manifest (righe evidenziate in giallo)

AndroidManifest.xml
============================================
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.luca.innocenti.autoboot">    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <application        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:roundIcon="@mipmap/ic_launcher_round"        android:supportsRtl="true"        android:theme="@style/AppTheme">        <activity android:name=".MainActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>

        <receiver
            android:name=".BootReceiver"
            android:enabled="true"
            android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <action android:name="android.intent.action.QUICKBOOT_POWERON" />
        </intent-filter>
    </receiver>

    </application>
</manifest>
============================================

Nella MainActivity si crea una nuova classe che riceve la notifica dell'avvenuto boot
(per vedere se il codice funziona si osservi logcat, non ci sono messaggi per l'utente)


MainActivity.kt
============================================
package com.luca.innocenti.autoboot
import android.content.BroadcastReceiverimport android.content.Contextimport android.content.Intentimport android.content.Intent.ACTION_BOOT_COMPLETED
import androidx.appcompat.app.AppCompatActivityimport android.os.Bundleimport android.util.Log
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

class BootReceiver : BroadcastReceiver() {

    override fun onReceive(c: Context, intent: Intent?) {
        val action = intent?.action        Log.d("ASD123123", "RECEIVED BOOT")
        val b = intent?.toUri(Intent.URI_INTENT_SCHEME)
        when (action) {
            ACTION_BOOT_COMPLETED -> startWork(c)
        }
    }


    private fun startWork(context: Context) {
        Log.d("Test", "Test")
    }
}

giovedì 27 febbraio 2020

Flutter webview

Ultimamente sto avendo parecchie noie da Play Store perche' alcune mie vecchie applicazioni realizzate con PhoneGap vengono ritenute pericolose per vulnerabilita' delle librerie contenute in phonegap e vengono rimosse in automatico. Ho cosi' cercato in giro un framework alternativo con caratteristiche simili a PhoneGap ed ho voluto provare a convertire una mia app PhoneGap in Flutter (anche perche' essendo un prodotto Google spero che non eliminino le app dallo store se compilate con Flutter)

Per installare Flutter si inizia scaricando il pacchetto del framework da questo link
Si scompatta e si mette in path la directory /flutter/bin
Per editare i progetti si puo' usare Android Studio aggiungendo i plugin di Flutter e Dart da Preferences (CTRL+ALT+S) e poi Plugin/Marketplace

Si crea quindi un nuovo progetto Flutter

si modifica il file pubsec.yaml per inserire la dipendenza dal plugin flutter_webview

dependencies:
  flutter:
    sdk: flutter
  flutter_webview_plugin: ^0.3.10+1

modificare il file pubspec.yaml per includere le directory di assets della

(attenzione che:
- le varie righe devono essere indentate in modo corretto
- deve essere creata una riga per ogni subdirectory contenuta in assets
- la directory assets non viene creata di default

flutter:
assets:
  - assets/
  - assets/css/
  - assets/altimetria/
  - assets/img/
  - assets/imgit/


per confronto questa e' parte dell'albero assets del mio progetto


Alla fine si crea popola con la webview e si fa puntare la url ai file locali

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
void main() {
  runApp(new MyApp());}

class MyApp extends StatefulWidget{
  _MyAppState createState() => _MyAppState();}

class _MyAppState extends State<MyApp> {
  @override  Widget build(BuildContext context) {
    return new MaterialApp(
        home: new WebviewScaffold(
          url: "file:///android_asset/flutter_assets/assets/index.html",        ),        debugShowCheckedModeBanner: false,    );  }
}

Debugger integrato ESP32S3

Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede  nell'ID USB della porta Jtag. Nel modulo...