Bluetooth Chat App Projekt

Mobile Anwendungen | Dozentin: Prof. Dr. Michael Cebulla | Wintersemester 24/25

I. Einführung

In diesem Projekt haben wir eine einfache mobile App entwickelt, mit der zwei Geräte über Bluetooth miteinander kommunizieren können. Mit der App können Nutzer in Echtzeit Textnachrichten austauschen, ohne dass sie auf eine Internetverbindung angewiesen sind. Ziel ist es, eine leicht verständliche und praktische Anwendung zu erstellen, die den Alltag in Situationen ohne stabile Internetverbindung oder bei direkter Geräteverbindung erleichtert.

Die Idee entstand aus dem Wunsch, eine unkomplizierte Lösung für Orte ohne Mobilfunknetz oder WLAN zu entwickeln. Unsere App richtet sich an Nutzer, die eine direkte Kommunikation zwischen zwei Geräten wünschen – sei es bei Outdooraktivitäten, auf Reisen oder in Notsituationen.

II. Software-Anforderungsanalyse

Die App ermöglicht es Benutzern, in Echtzeit Textnachrichten auszutauschen – ganz ohne Internetverbindung. Entwickelt für den Einsatz bei Ausfall von Mobilfunknetzen oder WLAN (z. B. bei Outdooraktivitäten, Reisen oder Notfällen), bietet die App eine intuitive Benutzeroberfläche und zuverlässigen Verbindungsaufbau über Bluetooth.

III. Funktionalität

IV. Szenarien

V. Architektur

Die Architektur der App umfasst mehrere Komponenten:

  1. Benutzeroberfläche (UI) Schicht: MainActivity und ChatMessageItem bilden die Benutzeroberfläche, in der Nachrichten angezeigt, eingegeben und verarbeitet werden.
  2. Kommunikationsmodul: BluetoothAdapter, AcceptThread, ConnectThread und ConnectedThread sorgen für den Aufbau und die Verwaltung der Bluetooth-Verbindungen sowie für den Nachrichtenaustausch. Das communicationService-Objekt repräsentiert hierbei den aktiven Kommunikationskanal.
  3. Integration von Sensoren: Der Licht- und der Beschleunigungssensor werden zur Steuerung von Bildschirmhelligkeit und zur Erkennung von Schüttelbewegungen verwendet, um im Notfall benutzerdefinierte Hilfemeldungen auszulösen.
  4. Standort und Systemdienste: LocationManager, Vibrator und System Settings ermöglichen die Erfassung von Standortdaten, haptisches Feedback und die Steuerung der Bildschirmhelligkeit.
  5. Verarbeitung und JSON-Erstellung: Nachrichten werden formatiert und, insbesondere im Fall von Notfällen, in JSON-Datenpakete umgewandelt.

Diese klare Trennung der Komponenten ermöglicht eine einfache Entwicklung, Testung und spätere Anpassungen.

Architektur Diagramm

VI. Code-Muster

Ein vereinfachter Codeabschnitt aus ChatMessageItem:

Dieser Code demonstriert, wie Chat-Nachrichten formatiert und angezeigt werden.

class ChatMessageItem(
    private val message: String,
    private val name: String,
    private val color: Int,
    private val isSentByMe: Boolean,
    private val timestamp: Long = System.currentTimeMillis()
) : Item<GroupieViewHolder>() {

    override fun getLayout(): Int {
        return R.layout.item_message
    }

    override fun bind(viewHolder: GroupieViewHolder, position: Int) {
        val tvFrom = viewHolder.itemView.findViewById<TextView>(R.id.tvFrom)
        val tvMessage = viewHolder.itemView.findViewById<TextView>(R.id.tvMessage)
        val tvTime = viewHolder.itemView.findViewById<TextView>(R.id.tvTime)
        val cardRoot = viewHolder.itemView.findViewById<MaterialCardView>(R.id.cardRoot)

        tvFrom.text = name
        tvMessage.text = message
        cardRoot.setCardBackgroundColor(color)

        val sdf = SimpleDateFormat("HH:mm", Locale.getDefault())
        tvTime.text = sdf.format(Date(timestamp))

        val params = cardRoot.layoutParams as FrameLayout.LayoutParams
        params.gravity = if (isSentByMe) Gravity.START else Gravity.END
        cardRoot.layoutParams = params
    }
}

Ein Auszug aus enableBluetooth() in der MainActivity:

Dieser Code zeigt, wie die Bluetooth-Funktionalität initialisiert und eine Verbindung aufgebaut wird.

private fun enableBluetooth() {
    bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
    if (bluetoothAdapter == null) {
        Snackbar.make(
            binding.root,
            "Ihr Gerät unterstützt kein Bluetooth.",
            Snackbar.LENGTH_LONG
        ).show()
        return
    }
    binding.tvDeviceName.text = bluetoothAdapter!!.name
    binding.tvDeviceAddress.text = bluetoothAdapter!!.address
    if (bluetoothAdapter?.isEnabled == false) {
        val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)
    }
    setupBluetoothClientConnection()
    AcceptThread().start()
}

Beispiel eines XML-Layouts:

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="8dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tvLogoText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Bluetooth ChatApp"
        android:textStyle="bold"
        android:textColor="@color/blueChatText"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <!-- Weitere UI-Elemente ... -->

</androidx.constraintlayout.widget.ConstraintLayout>

VII. Implementierung

Erste Version: Grundlegende Funktionen wie Nachrichtenversand und Bluetooth-Verbindung wurden implementiert.

Version 2: Neues Design (Re-Skinned Project) wurde eingeführt, Dark Theme-Probleme traten jedoch auf.

Version 3: Erweiterungen wie Zeitstempel und Anpassungen im Chat-Layout zur Verbesserung der Stabilität wurden integriert.

Version 4 und 4.1: Neue Features wie Vibrationsfunktion und Notfallbutton wurden implementiert.

Letzte Version: Die Benutzeroberfläche wurde komplett überarbeitet und an moderne Designstandards angepasst. Zusätzlich wurden neue Funktionen integriert, wie die automatische Anpassung der Bildschirmhelligkeit mittels Umgebungslichtsensor und eine innovative Funktion, bei der durch kräftiges Schütteln des Geräts eine benutzerdefinierte Hilfemeldung ausgelöst wird.

VIII. Testen

Es wurden funktionale und Usability-Tests auf drei verschiedenen Geräten mit unterschiedlichen Android-Versionen durchgeführt, um die Kompatibilität und Zuverlässigkeit der App zu gewährleisten.

IX. Herausforderungen

Während der Entwicklung traten Probleme auf, wie z.B. das automatische Schließen der App bei deaktiviertem Standort auf älteren Android-Versionen (Android 10) und die fehlerhafte Darstellung von Notfallnachrichten (als JSON-Datenpaket statt formatierten Text). Auf Geräten mit Android-Versionen über 12 trat dieser Fehler nicht auf (siehe Bild 1).

Screenshot von Android 12 Gerät

Bild 1

Auf dem Gerät des Empfängers erscheint die Nachricht jedoch nur als JSON-Datenpaket, was zu einer unklaren Darstellung der Information führt (siehe Bild 2).

Screenshot der JSON-Datenpaket-Anzeige

Bild 2

Zusätzlicher Screenshot oder Detailansicht

Bild 3

Weitere Versuche, erweiterte Funktionen wie Nachrichtenstatus (gesendet, empfangen, gelesen) und Multimedia-Unterstützung (Bilder, Videos, Sprachnachrichten, Dateien) zu integrieren, waren nicht erfolgreich.

X. Fazit

Das Projekt hat gezeigt, dass auch mit einfachen Mitteln eine zuverlässige Verbindung zwischen mobilen Geräten hergestellt werden kann. Trotz einiger Herausforderungen, insbesondere bei der Kompatibilität älterer Android-Versionen, konnte eine praktische Lösung für die direkte Kommunikation geschaffen werden.

Wichtige Erkenntnisse: Einfache Kommunikation, stabile Verbindung und die Bedeutung von Teamarbeit bei der Problemlösung.

XI. Installation und Setup

Version Datum Beschreibung APK
5.0 16.03.2025 Komplett überarbeitete Benutzeroberfläche, automatische Bildschirmhelligkeitsanpassung mittels Lichtsensor und Notfall-Hilfemeldung per Schütteln. APK herunterladen
4.1 Kleinere Bugfixes.
4.0 Implementierung der Vibrationsfunktion und des Notfallbuttons.
3.0 Erweiterungen wie Zeitstempel und Anpassungen im Chat-Layout zur Verbesserung der Stabilität.
2.0 Re-Skinned Project: Neues Design, Dark Theme-Probleme teilweise vorhanden.
1.0 Grundlegende Funktionen wie Nachrichtenversand und Aufbau der Bluetooth-Verbindung.

XII. Sensoreinsatz

Im folgenden Codeabschnitt wird gezeigt, wie die Sensoren (Licht- und Beschleunigungssensor) in der App verwendet werden, um die Bildschirmhelligkeit automatisch anzupassen und bei kräftigem Schütteln eine benutzerdefinierte Notfallnachricht auszulösen:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    binding.etReplyLayout.visibility = View.GONE
    binding.btnSendToConnected.visibility = View.GONE

    vibrator = if (Build.VERSION.SDK_INT >= 31) {
        try {
            val vibratorManagerClass = Class.forName("android.os.VibratorManager")
            val managerService = getSystemService(Class.forName("android.content.Context")
                .getField("VIBRATOR_MANAGER_SERVICE")
                .get(null) as String)
            val getDefaultMethod = vibratorManagerClass.getMethod("getDefaultVibrator")
            getDefaultMethod.invoke(managerService) as Vibrator
        } catch (e: Exception) {
            getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
        }
    } else {
        getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
    }

    // Initialize location manager
    locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager

    sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
    lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)

    binding.btnSaveEmergencyMessage.setOnClickListener {
        val msg = binding.etEmergencyMessage.text.toString().trim()
        if (msg.isNotEmpty()) {
            savedEmergencyMessage = msg
            // Düzenleme modunu gizle, Anzeige-Modus aktivieren
            binding.layoutEmergencyEdit.visibility = View.GONE
            binding.layoutEmergencyDisplay.visibility = View.VISIBLE
            binding.tvEmergencyMessage.text = savedEmergencyMessage
            Toast.makeText(this, "Notfallnachricht aufgezeichnet.", Toast.LENGTH_SHORT).show()
        } else {
            Toast.makeText(this, "Die Nachricht kann nicht leer sein!", Toast.LENGTH_SHORT).show()
        }
    }

    binding.btnEditEmergencyMessage.setOnClickListener {
        binding.layoutEmergencyDisplay.visibility = View.GONE
        binding.layoutEmergencyEdit.visibility = View.VISIBLE
        binding.etEmergencyMessage.setText(savedEmergencyMessage)
    }

    accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)

    // Check location permissions
    checkLocationPermissions()

    setup()
    setupEmergencyButton()
    enableBluetooth()
}

XIII. Nutzungsszenarien-Video

Klicken Sie hier, um das Video anzusehen oder nutzen Sie den alternativen Link.

XIV. Hilfe und Kontakt

Bei Fragen oder Problemen wenden Sie sich bitte an: