Contexte Ressources utilisées Firebase Authentification Cloud Formulaires Actualité Points d'accès Dématérialisation Documents

Application Android

Eclisse : Déstiné aux agents sur le terrain


Contexte de l'application mobile


FEROWAY, l'entreprise où j'effectue mon alternance conçoit des systèmes complets de sécurité ferroviaire, depuis la préparation des travaux, en passant par l’acheminement du matériel, jusqu’à la sécurisation des chantiers.


FEROWAY emploie notamment des conducteurs de trains, qui sont assurés d'une aide 24h/24, 7J/7 grâce à un PC de commandement. Le PC et les conducteurs de trains s'échangent différentes informations par téléphone.

L'application Eclisse à été initialement créer pour ajouter plusieurs formulaires prédéfinis qui seront remplis par les conducteurs et envoyés directement sur la boite mail du PC de commandement.

Elle a pour utilité une simplication de l'envoie et qui garantit d'avoir la totalité des informations nécessaires


Après avoir fait des bétâs tests sur le terrains, avec un collègue qui travaille au PC de commandement et qui trouve les idées d'améliorations de l'application, beaucoup de demandes d'amélioratio,s de l'applications notamment en matières de services pour les conducteurs ont remontées.

Grâce à cette intérêt, nous avons été pousés à continuer le développement de l'application.


Vous verez donc sur cette page l'intégralité du projet : dans un premier temps les ressources & outils utilisés , puis les fonctionnalités proposées.


Ressources utilisées


Les utilisateurs disposant d'un téléphone Samsung, il fallait donc développé une application déstiné aux système d'exploitation Android.

En effectuant des recherches appronfondies sur internet, l'IDE Android Studio est désigné comme l'environnement de développement officiel.



Le langage utilisé sous Android Studio est le Java. C'est le langage Android le plus utilisé dans le développement mobile.

L’un de ses plus grands avantages est que les logiciels créés avec ce langage peuvent être facilement installés et exécutés sur différents systèmes d’exploitation, que ce soit Windows, Mac OS, Linux ou autre.


Ce langage de balisage est utilisé pour gérer l’affichage des contenus sur l’écran.

Il n’est pas indispensable pour créer une application Android, mais il facilite le développement en permettant de séparer l’affichage des algorithmes.

Avec XML, on gagne du temps et on simplifie le code de l’application, ce qui permet d’éviter des erreurs.

Toute l'entreprise FEROWAY utilise le système d'exploiation WIndows 10.

Pour pouvoir utilisé le Playstore de Google, il faut acheter une licence qui coûte 25$ et que l'on garde à vie.

C'est à partir de cette console que l'on accède à notre publication de l'application.


Firebase


Google possède sa plateforme mobile pour faciliter la création de Backend à la fois performant et scalable, son nom : Firebase.


De manière simple, la plateforme de développement Firebase vous accompagne dans le développement rapide des applis pour le mobile et le web.


L’idée était de fournir aux particuliers et aux professionnels une alternative au processus complexe de la création et la maintenance d’une architecture serveur.

En outre, la plateforme accepte des utilisateurs multiples simultanément sans que cela affecte le fonctionnement de la plateforme.

Avec de nombreuses fonctionnalités intuitives, la plateforme est vraiment pratique.


Avec firebase, vous avez à votre disposition de nombreuses API intuitives répertoriées dans un SDK unique.

Toutes ces API vous aident non seulement à gagner du temps, mais contribuent aussi à réduire le nombre d’intégrations que votre application doit gérer.

Vous avez l’occasion d’utiliser une plateforme qui fournit une intégration rapide et efficace à tous les produits issus de là.


Étant un produit de Google, Firebase utilise l’infrastructure et s’adapte très rapidement en cas de mise à jour de l’application.

Pour conclure, vous avez la liberté de développer votre firebase app dans des conditions idéales, car la plateforme vous fournit une solution évolutive, complète et boostée par Google.


Vous trouverez ici un guide complet en français sur l'utilisation de Firabse avec le langage java.


Authentification sécurisée


Vous pouvez utiliser l'authentification Firebase pour permettre à vos utilisateurs de s'authentifier avec Firebase à l'aide de leurs adresses de messagerie et de leurs mots de passe, ainsi que pour gérer les comptes de mots de passe de votre application.


Nous devons utiliser et installer le SDK Firebase Authentication afin de créer notre premier système d'authentification.



Exemple du code de Firebase Authentication
                            
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.OAuthProvider;

public class MicrosoftActivity extends AppCompatActivity {

    private FirebaseAuth auth;
    private OAuthProvider.Builder provider;

    @Override
    protected void onCreate(Bundle savedInstanceState) {    
        super.onCreate(savedInstanceState);

        provider = OAuthProvider.newBuilder("microsoft.com");
        provider.addCustomParameter("tenant", "XXXX");

        auth = FirebaseAuth.getInstance();

        btn_log.setOnClickListener(v -> LogIn_button());
    }
                
    private void readData() {
        auth
            .startActivityForSignInWithProvider(this, provider.build())
            .addOnSuccessListener(
                    authResult -> {
                        new Download(progressBar, textView_loading, this);
                        // User is signed in.
                        // IdP data available in
                        // authResult.getAdditionalUserInfo().getProfile().
                        // The OAuth access token can also be retrieved:
                       // authResult.getCredential().getAccessToken().

                        })
            .addOnFailureListener(
                    e -> {
                        // Handle failure   
                        Log.e("TAAAAAAAAG", e.getLocalizedMessage());
                        Log.e("TAAAAAAAAG", e.getMessage());
                        Log.e("TAAAAAAAAG", String.valueOf(e.getCause()));
                        progressBar.setVisibility(View.GONE);
                        textView_loading.setVisibility(View.GONE);
                        btn_log.setVisibility(View.VISIBLE);
                    });
    }
}
                            

Cloud


Stockage sur le Cloud Firebase Storage (Stockage)


Firebase Storage fournit des téléchargements de fichiers sécurisés pour vos applications Firebase, quelle que soit la qualité du réseau.

Vous pouvez l'utiliser pour stocker des images, du son, de la vidéo ou tout autre contenu généré par l'utilisateur.

Firebase Storage est soutenu par Google Cloud Storage, un service de stockage d'objets puissant, simple et économique.


Firebase Storage stocke vos fichiers dans un compartiment Google Cloud Storage partagé avec l'application Google App Engine par défaut, les rendant ainsi accessibles via les API Firebase et Google Cloud.

Cela vous permet de télécharger et de télécharger des fichiers à partir de clients mobiles via Firebase.


Firebase Storage s'intègre parfaitement à l'authentification Firebase pour identifier les utilisateurs et fournit un langage de sécurité déclaratif qui vous permet de définir des contrôles d'accès sur des fichiers individuels ou des groupes de fichiers afin de rendre vos fichiers publics ou privés.



Exemple du code pour l'utilisation de Firebase Storage (Stockage)
import com.google.firebase.storage.FirebaseStorage;   

public Download(ProgressBar mprogressBar, TextView mtextview, MicrosoftActivity mymicrosoftActivity) {

    progressBar = mprogressBar;
    textView = mtextview;
    this.microsoftActivity = mymicrosoftActivity;

    storage = FirebaseStorage.getInstance();

    //Supp anciennement dir////////////
    File file_supp = new File(Environment.getExternalStorageDirectory() + "/.ETF/");
    if (file_supp.exists())
        deleteDir(file_supp);
    ///////////////////////////////////

    readData();
}

@SuppressLint("SetTextI18n")
private void readData() {
    File file = new File(dir);

    if (!file.exists()) {
        file.mkdir();
    }
    if (new File(dir).list().length != list.size()) {
        textView.setText("Téléchargement en cours...");
        //dialog.setCanceledOnTouchOutside(false);

        List<Task> tasks = new ArrayList<>();
//And so on
        for (int i = 0; i < list.size(); i++) {
            File file2 = new File(file.getPath(), list.get(i));
            if (!file2.exists()) {
                tasks.add(storage.getReference().child(list.get(i)).getFile(file2));
            }
        }

        Tasks.whenAllSuccess(tasks).addOnSuccessListener(objects -> {
            CheckEtfServices check = new CheckEtfServices();

            if (check.getCheeeck()) {
                boolean bool = microsoftActivity.sharedPref.getBoolean("authentification", false);

                if (!bool) {
                    SharedPreferences.Editor editor = microsoftActivity.sharedPref.edit();
                    editor.putBoolean("authentification", true);
                    editor.apply();
                }
                microsoftActivity.startActivity(new Intent(microsoftActivity, DrawerActivity.class));
                microsoftActivity.finish();
                //dialog.dismiss();
            } else {
                //dialog.dismiss();
                AlertDialog.Builder mBuilder = new AlertDialog.Builder(Objects.requireNonNull(microsoftActivity));
                @SuppressLint("InflateParams") View mView = microsoftActivity.getLayoutInflater().inflate(R.layout.layout_alert_connection, null);
                TextView textVieww = mView.findViewById(R.id.textview_connect);
                String nom = Objects.requireNonNull(FirebaseAuth.getInstance().getCurrentUser()).getDisplayName();
                textVieww.setText("Cher " + nom);
                mBuilder.setView(mView);
                final AlertDialog dialog_ = mBuilder.create();
                FirebaseAuth.getInstance().getCurrentUser().delete();
                dialog_.show();
            }
        });

    } else {
        final List<Task> tasks_metadata = new ArrayList<>();

        for (int i = 0; i < list.size(); i++) {
            int finalI = i;
            int finalI1 = i;
            storage.getReference().child(list.get(i)).getMetadata().addOnSuccessListener(storageMetadata -> {
                final SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss", Locale.getDefault());
                sdf.setTimeZone(TimeZone.getTimeZone("France/Paris"));

                Date date_in = null;
                File file2;
                file2 = new File(file.getPath(), list.get(finalI));
                try {
                    date_in = sdf.parse(sdf.format(new Date(file2.lastModified())));
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                Date date = null;
                try {
                    date = sdf.parse(sdf.format(new Date(storageMetadata.getUpdatedTimeMillis())));
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                assert date != null;
                String date_time = sdf.format(date.getTime());
                assert date_in != null;
                String date_in_time = sdf.format(date_in.getTime());

                if (date.compareTo(date_in) > 0) {
                    textView.setText("Téléchargement en cours...");
                    tasks_metadata.add(storage.getReference().child(list.get(finalI)).getFile(file2));
                } else if (date.compareTo(date_in) == 0 && date_time.compareTo(date_in_time) > 0) {
                    textView.setText("Téléchargement en cours...");
                    tasks_metadata.add(storage.getReference().child(list.get(finalI)).getFile(file2));
                } 
            });
        }
    }
}

                                





Base de donné sur le Cloud Firebase Firestore (Database)


Cloud Firestore est une base de données de documents NoSQL sans serveur, cloud native, entièrement gérée et rapide.

Ce service simplifie le stockage, la synchronisation et l'interrogation des données pour les applications Web, mobiles et IoT à l'échelle mondiale.

Ses bibliothèques clientes permettent une synchronisation en direct et un fonctionnement hors connexion.


Bien que l'interface Cloud Firestore présente de nombreuses fonctionnalités identiques aux bases de données traditionnelles, elle diffère d'une base de données NoSQL par la manière dont elle décrit les relations entre les objets de données.

Exemple du code pour l'utilisation de Firebase Firestore (Database)
                        
FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();
list = new ArrayList() {
};


firebaseFirestore.collection("Files").get().addOnCompleteListener(task -> {
    if (task.isSuccessful()) {
        int j = 0;
        for (int i = 0; i < Objects.requireNonNull(task.getResult()).size(); i++) {
            list.add(Objects.requireNonNull(task.getResult().getDocuments().get(i).get("image")).toString());
            j++;
        }
        if (j == task.getResult().size()) {
            readData();
        }
    }
});
                                

Formulaires Google Forms


Google Forms permet de créer des formulaires personnalisés pour réaliser des enquêtes et des questionnaires en toute simplicité, et sans frais supplémentaires.

Les données sont recueillies dans une feuille de calcul et vous pouvez les analyser directement dans Google Sheets.


Dans notre cas, lors de la finalisation du formulaire par l'utilisateur un email est envoyé au poste de commandement.

L'utilisateur à aussi la possibilité de reçevoir une copie du formulaires sur sa boîte mail.


Exemple du code pour l'ouverture du formulaires
import androidx.browser.customtabs.CustomTabsIntent;

//Email de l'utilisateur
String mail_final = ""String.valueOf(text.getText())"";

String SITE_URL_ZD_ALLER = "https://docs.google.com/forms/XXXXXX/viewform?emailAddress=" + mail_final;

// Initialize intentBuilder
CustomTabsIntent.Builder intentBuilder = new CustomTabsIntent.Builder();

// Set toolbar(tab) color of your chrome browser
intentBuilder.setToolbarColor(ContextCompat.getColor(Objects.requireNonNull(getActivity()).getApplicationContext(), R.color.colorPrimary));

// Define entry and exit animation
intentBuilder.setExitAnimations(getActivity().getApplicationContext(), R.anim.right_to_left_end, R.anim.left_to_right_end);
intentBuilder.setStartAnimations(getActivity().getApplicationContext(), R.anim.left_to_right_start, R.anim.right_to_left_start);
intentBuilder.setSecondaryToolbarColor(ContextCompat.getColor(getActivity().getApplicationContext(), R.color.colorPrimary));


// build it by setting up all
customTabsIntent = intentBuilder.build();
customTabsIntent.intent.setPackage("com.android.chrome");
customTabsIntent.intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

dialog = mBuilder.create();

                                  


Fil d'actualités


Un fil d'actualités à été ajouté à l'application Eclisse qui permet au PC de commandement et au pôle QSE de partager différentes informations.


Exemple du code qui utilise le Cloud Firebase Firestore & Storage
private void readData() {
    FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();

    list = new ArrayList() {};

    firebaseFirestore.collection("Actualite").get().addOnCompleteListener(task -> {
        if (task.isSuccessful()) {
            for (int i = 0; i < Objects.requireNonNull(task.getResult()).size(); i++) {
                list.add(Objects.requireNonNull(task.getResult().getDocuments().get(i).get("position")).toString());
                list.add(Objects.requireNonNull(task.getResult().getDocuments().get(i).get("titre")).toString());
                list.add(Objects.requireNonNull(task.getResult().getDocuments().get(i).get("texte")).toString());
                list.add(Objects.requireNonNull(task.getResult().getDocuments().get(i).get("image")).toString());

                list_size++;
            }
            listPosition();
        }
    });
}
                               

Point d'accès (Maps ou Waze)


Les agents sur le terrains se rendent quotidiennement sur différents chantier situés sur toutes la France.

Ils ont donc besoins de différents points d'accès (à l'aide de coordonnées géographiques), et obtenues lors de l'acquisation de nouveaux chantiers.


Une recherche des points d'accès (trier dans l'ordre des "Points Kilométriques) à été ajoutée à l'application mobile Eclisse.

La recherche par l'utilisateur seffectue selon le secteur, puis selon les chantiers.

Il a alors le choix de copier le PK dans le presse papier, se rendre aux coordonnées grâce à Google Maps ou grâce à Waze.



Exemple du code qui 'get' les données d'un fichier Excel
                                   
Workbook workBook = Workbook.getWorkbook(filename);

// Référence vers l'onglet
Sheet onglet1 = workBook.getSheet(0);
Cell cellule;
                    
for (int i = (onglet1.getRows() - 1); i > 0; i--) {
    // Contenu de la cellule
    cellule = onglet1.getCell(1, i);
    if (!cellule.getContents().equals(""))
        pk.add("PK" + cellule.getContents());
    else
        pk.add("");
    cellule = onglet1.getCell(0, i);
    prenoms.add(cellule.getContents());
    cellule = onglet1.getCell(2, i);
    geo.add(cellule.getContents());
}
                               

Dématerialisation partielle


Une dématerialisation partielle à été faite depuis l'application mobile Eclisse :

---- Elle permet d'obtenir différents documents selon la machine séléectionnée.

---- Grâce à des recherches il est possible d'obtenir les abréviations des gares de France, l'annuaires téléphonique des postes de France, l'annuaire téléphonique de toutes l'agence.



Exemple du code qui permet l'affichage d'un fichier PDF
                                   
PDFView pdfviewer = v.findViewById(R.id.pdfviewer);

pdfviewer.fromAsset("manuel_BB60000.pdf").load();
                        
//Bouton quitter : permet de revenir aux choix de la machine
FloatingActionButton back = v.findViewById(R.id.back);
back.setOnClickListener(v1 -> {
    Fragment fragment;
                        
    fragment = new HotlineFragment();
    String title = "Hotlne Machine";
                        
    FragmentTransaction ft = Objects.requireNonNull(getActivity()).getSupportFragmentManager().beginTransaction();
    //ft.setCustomAnimations(R.anim.slide_in_from_left, R.anim.slide_out_to_right);
    ft.replace(R.id.mainFrame, fragment);
    ft.commit()
    if (getActivity().getActionBar() != null) {
        getActivity().getActionBar().setTitle(title);
    }
});