Psyter Care Provider - Android Application

Version: 2.0.33 (Build 68)
Package: com.psyter.www.careprovider
Min SDK: 21 (Android 5.0 Lollipop)
Target SDK: 33 (Android 13)
Last Updated: November 2025


Table of Contents

  1. Overview
  2. Prerequisites
  3. Project Structure
  4. Setup Instructions
  5. Configuration
  6. Building the Application
  7. Key Features
  8. Architecture
  9. Dependencies
  10. Firebase Integration
  11. API Integration
  12. Video Call Implementation
  13. Navigation Structure
  14. Common Issues & Troubleshooting
  15. Testing
  16. Release Process
  17. Contributing Guidelines

Overview

The Psyter Care Provider Android application is the healthcare professional companion to the Psyter mental health telemedicine platform. This app enables therapists, psychologists, psychiatrists, and other mental health professionals to:

  • Manage patient appointments and schedules
  • Conduct secure video therapy sessions
  • Review and respond to patient assessments
  • Assign and review therapeutic homework
  • Communicate with patients via in-app messaging
  • Manage prescriptions and medical documentation
  • Track patient progress and history

Technology Stack

  • Language: Java (primary) + Kotlin (newer features)
  • Build System: Gradle 7.4.0 with Android Gradle Plugin 4.2.2
  • Minimum Android: API 21 (Lollipop)
  • Target Android: API 33 (Android 13)
  • Video SDK: VideoSDK 0.1.31
  • Architecture: MVVM with LiveData and ViewBinding
  • Networking: Fast Android Networking library
  • Real-time Communication: WebSocket (nv-websocket-client)
  • Push Notifications: Firebase Cloud Messaging (FCM)
  • Image Loading: Glide 4.16.0
  • Authentication: OAuth 2.0 with JWT tokens

Prerequisites

Required Software

  1. Android Studio: Arctic Fox (2020.3.1) or later (recommended: Latest stable)
  2. JDK: Java Development Kit 8 or 11
  3. Android SDK:
    - SDK Platform 33 (Android 13)
    - Build Tools 33.x.x
    - Android SDK Platform-Tools
    - Android SDK Command-line Tools
  4. Git: For version control
  5. Gradle: 7.4+ (bundled with Android Studio)

Development Environment Setup

Windows

# Install Android Studio from https://developer.android.com/studio
# Set JAVA_HOME environment variable
$env:JAVA_HOME = "C:\Program Files\Java\jdk-11.0.x"
$env:PATH += ";$env:JAVA_HOME\bin"

# Set ANDROID_HOME
$env:ANDROID_HOME = "$env:LOCALAPPDATA\Android\Sdk"
$env:PATH += ";$env:ANDROID_HOME\platform-tools;$env:ANDROID_HOME\tools"

macOS/Linux

# Set JAVA_HOME
export JAVA_HOME=$(/usr/libexec/java_home -v 11)

# Set ANDROID_HOME
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools

API Access

You’ll need access to:
- Psyter Backend API - REST API endpoints
- NodeServer WebSocket - Real-time collaboration server
- Firebase Project - FCM credentials (google-services.json)
- VideoSDK Account - Video call functionality


Project Structure

AndroidCareProvider/
├── app/
│   ├── build.gradle                    # App-level build configuration
│   ├── google-services.json            # Firebase configuration (DEV)
│   ├── google-services_dev.json        # Firebase configuration backup
│   ├── proguard-rules.pro             # ProGuard obfuscation rules
│   ├── libs/                          # Local AAR/JAR libraries
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml    # App manifest & permissions
│           ├── java/com/psyter/www/
│           │   ├── MainApplication.java              # Application entry point
│           │   ├── MyFirebaseMessagingService.java  # FCM handler
│           │   ├── MessageObservable.java           # Event bus for messaging
│           │   │
│           │   ├── CareProvider/            # Care provider specific features
│           │   │   ├── Activities/          # Care provider activities
│           │   │   │   ├── BaseCarePActivityMain.java      # Main container (deprecated pattern)
│           │   │   │   ├── BaseClientActivityMain.java     # New main container with bottom nav
│           │   │   │   ├── OneToOneCallActivity.kt         # Video call UI (VideoSDK)
│           │   │   │   ├── ChatMainActivity.java           # Patient messaging
│           │   │   │   ├── ConversationActivity.java       # Chat conversation view
│           │   │   │   ├── CPHistoryActivity.java          # Patient history overview
│           │   │   │   ├── ClientHistoryActivity.java      # Client session history
│           │   │   │   ├── InitialAssessmentAcitivity.java # Create assessments
│           │   │   │   ├── InitialAssessmentViewAcitivity.java # View assessments
│           │   │   │   ├── FilledAssessmentViewActivity.java   # Patient responses
│           │   │   │   ├── NewHomeWorkActivity.java        # Assign homework
│           │   │   │   ├── HomeWorkCheckActivity.java      # Review homework
│           │   │   │   ├── PrescriptionActivity.java       # Manage prescriptions
│           │   │   │   ├── PaymentsDetailActivity.java     # Payment history
│           │   │   │   ├── ReferralActivity.java           # Patient referrals
│           │   │   │   └── ReserveSlotActivity.java        # Schedule management
│           │   │   │
│           │   │   ├── Fragments/           # Care provider fragments
│           │   │   │   ├── MyAppointCarePFragment.java     # Appointments list
│           │   │   │   ├── PersonalInfoFragment.java       # Profile management
│           │   │   │   ├── ScheduleFragment.java           # Weekly schedule
│           │   │   │   └── ...
│           │   │   │
│           │   │   ├── Adapters/            # RecyclerView adapters
│           │   │   ├── DataModels/          # POJO data classes
│           │   │   ├── Schedule/            # Scheduling logic
│           │   │   └── WorkCancelReceiver.java  # Background work cancellation
│           │   │
│           │   ├── Client/                  # Patient-facing features (shared code)
│           │   │   ├── Activities/          # Client activities
│           │   │   ├── Fragments/           # Client fragments
│           │   │   ├── Adapters/            # Client adapters
│           │   │   └── BookSlots/           # Appointment booking
│           │   │
│           │   ├── CommonUser/              # Shared user features
│           │   │   ├── Activities/          # Auth, profile, search
│           │   │   ├── Fragments/           # Shared fragments
│           │   │   └── Adapters/            # Shared adapters
│           │   │
│           │   ├── Registration/            # Auth & onboarding
│           │   │   └── Activities/
│           │   │       ├── SplashActivity.java         # App entry (launcher)
│           │   │       ├── LoginActivity.java          # Login screen
│           │   │       ├── RegisterCareProviderActivity.java # Provider registration
│           │   │       ├── UserSelectionActivity.java  # User type selection
│           │   │       └── QuestionaireActivity.java   # Initial questionnaire
│           │   │
│           │   ├── Collaboration/           # Video call & WebRTC
│           │   │   ├── Presence/            # Presence & call management
│           │   │   │   ├── CollaborationMain.java      # WebRTC session (legacy)
│           │   │   │   ├── IncomingCall.java           # Incoming call UI
│           │   │   │   └── FloatingViewService.java    # Picture-in-picture
│           │   │   ├── Common/              # Bluetooth & audio helpers
│           │   │   └── NetWorkDetectionHelpers/        # Connectivity monitoring
│           │   │
│           │   ├── Scheduling/              # Appointment scheduling
│           │   │   ├── WeeklySchedule/      # Weekly view components
│           │   │   └── Services/            # Background slot sync
│           │   │
│           │   ├── Stats/                   # Utilities & helpers
│           │   │   ├── Utils.java           # Global utility methods
│           │   │   ├── MySharedPreferences.java  # Preferences wrapper
│           │   │   ├── LocaleUtils.java     # Localization (AR/EN)
│           │   │   ├── LangHelper.java      # Language switching
│           │   │   └── TransparentProgressDialog.java  # Loading dialogs
│           │   │
│           │   ├── navigation/              # Bottom navigation (Kotlin)
│           │   │   └── TabManager.kt        # NavController management
│           │   │
│           │   ├── bottomnavbar/            # Custom bottom nav component
│           │   │
│           │   ├── views/                   # Custom views & activities
│           │   │   ├── activity/
│           │   │   │   ├── AddPrescriptionActivity.kt   # Prescription UI
│           │   │   │   ├── RegisterActivity.kt          # Registration flow
│           │   │   │   └── OnboardingActivity.kt        # First-run experience
│           │   │   └── fragments/           # Onboarding fragments
│           │   │
│           │   ├── workers/                 # WorkManager background tasks
│           │   │
│           │   └── BranchEvents/            # Branch.io deep linking
│           │
│           └── res/
│               ├── layout/                  # XML layouts
│               ├── drawable/                # Images & vector graphics
│               ├── values/                  # Strings, colors, styles
│               ├── navigation/              # Navigation graphs
│               └── xml/                     # Network security config
│
├── duo-navigation-drawer/         # Custom navigation drawer library
├── intlphoneinput/                # International phone input library
├── gradle/                        # Gradle wrapper
├── build.gradle                   # Project-level build config
├── settings.gradle                # Project modules
└── README.md                      # Original README (stub)

Key Package Responsibilities

Package Purpose
CareProvider/ Care provider-specific features (main business logic)
Client/ Patient-facing features (shared with patient app)
CommonUser/ Features common to both patient and provider users
Registration/ Authentication, login, signup flows
Collaboration/ Video calling with WebRTC/VideoSDK
Scheduling/ Appointment booking and calendar management
Stats/ Utilities, preferences, helpers
navigation/ Bottom navigation tab management (Kotlin)
views/ Custom UI components and newer Kotlin activities
workers/ Background sync tasks (WorkManager)
BranchEvents/ Deep linking and attribution

Setup Instructions

1. Clone the Repository

git clone <repository-url>
cd Psyter/AndroidCareProvider

2. Open in Android Studio

  1. Launch Android Studio
  2. Select File → Open
  3. Navigate to Psyter/AndroidCareProvider
  4. Click OK
  5. Wait for Gradle sync to complete

3. Configure Firebase

Option A: Use Existing Configuration

The repository includes google-services.json (dev environment). For production:

  1. Obtain the production google-services.json from Firebase Console
  2. Replace app/google-services.json
  3. Sync Gradle

Option B: Set Up New Firebase Project

  1. Go to Firebase Console
  2. Create new project or select existing
  3. Add Android app:
    - Package name: com.psyter.www.careprovider
    - App nickname: Psyter Care Provider
    - Debug signing certificate: (optional for development)
  4. Download google-services.json
  5. Place in app/ directory
  6. Enable Firebase Cloud Messaging (FCM)
  7. Enable Firebase Crashlytics

4. Configure API Endpoints

API base URLs are stored in SharedPreferences and configured at runtime. For development, you can hardcode them in Stats/Utils.java:

// Stats/Utils.java
public static String BaseURL = "https://dev2.innotech-sa.com/Psyter/Master/APIs/";
public static String BaseURLDocument = "https://dev2.innotech-sa.com/Psyter/Master/APIs/";
public static String BaseURLVideo = "https://dev2.innotech-sa.com/Psyter/Master/APIs/";
public static String BaseURLPayment = "https://dev2.innotech-sa.com/Psyter/Master/Web/Client/BookingPaymentFromMobile?dataString=";
public static String WebSocketURL = "wss://your-server.com:8443";

Production Note: These should be fetched from a remote config service, not hardcoded.

5. Install NDK (for VideoSDK)

VideoSDK requires Android NDK:

  1. Open Tools → SDK Manager
  2. Navigate to SDK Tools tab
  3. Check NDK (Side by side) - version 23.1.7779620
  4. Click Apply and wait for installation

6. Sync Gradle

./gradlew clean build

Or in Android Studio: File → Sync Project with Gradle Files


Configuration

Product Flavors

The app supports two flavors (though currently unused):

Flavor Package Purpose
client com.psyter.www Patient app (not used in this repo)
careprovider com.psyter.www.careprovider Care provider app

Build the care provider flavor:

./gradlew assembleCareProviderRelease

Build Types

Build Type Debuggable Minified Use Case
debug Development
release Production (ProGuard disabled)

⚠️ Security Note: ProGuard is currently disabled (minifyEnabled false). Enable for production builds.

Permissions

The app requires the following permissions (see AndroidManifest.xml):

Essential:
- INTERNET - API and WebSocket communication
- ACCESS_NETWORK_STATE - Network connectivity monitoring
- CAMERA - Video calls
- RECORD_AUDIO - Video calls and voice messages
- MODIFY_AUDIO_SETTINGS - Audio routing during calls

Storage:
- READ_EXTERNAL_STORAGE - Access patient documents
- WRITE_EXTERNAL_STORAGE - Save downloaded files
- READ_MEDIA_IMAGES - Android 13+ media access

Communication:
- POST_NOTIFICATIONS - Push notifications (Android 13+)
- WAKE_LOCK - Keep device awake during calls

Bluetooth:
- BLUETOOTH - Bluetooth headset support
- BLUETOOTH_ADMIN - Bluetooth device management
- BLUETOOTH_CONNECT - Android 12+ Bluetooth

Other:
- SYSTEM_ALERT_WINDOW - Picture-in-picture during calls
- READ_PHONE_STATE - Call state awareness

Network Security Configuration

res/xml/network_security_config.xml allows cleartext traffic for development:

<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

⚠️ Production Warning: Disable cleartext traffic in production. Use HTTPS only.


Building the Application

Debug Build

# Command line
./gradlew assembleCareProviderDebug

# Android Studio
Build  Build Bundle(s) / APK(s)  Build APK(s)

Output: app/build/outputs/apk/careprovider/debug/app-careprovider-debug.apk

Release Build

# Generate signed APK
./gradlew assembleCareProviderRelease

# Generate signed App Bundle (recommended for Play Store)
./gradlew bundleCareProviderRelease

Signing Configuration:

Create keystore.properties in project root:

storePassword=your_store_password
keyPassword=your_key_password
keyAlias=your_key_alias
storeFile=path/to/keystore.jks

Add to app/build.gradle:

def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

android {
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile file(keystoreProperties['storeFile'])
            storePassword keystoreProperties['storePassword']
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

Install on Device

# Via ADB
adb install app/build/outputs/apk/careprovider/debug/app-careprovider-debug.apk

# Or in Android Studio
Run  Run 'app'

Key Features

1. Appointment Management

  • Location: CareProvider/Fragments/MyAppointCarePFragment.java
  • View upcoming, past, and cancelled appointments
  • Filter by date range
  • Quick actions: Start session, reschedule, cancel
  • Appointment details: patient info, diagnosis, session notes

2. Video Consultations (VideoSDK)

  • Location: CareProvider/Activities/OneToOneCallActivity.kt
  • Technology: VideoSDK 0.1.31
  • Features:
  • HD video calls (720p/1080p)
  • Audio-only option
  • Screen sharing
  • Camera switching (front/back)
  • Mute/unmute audio
  • Picture-in-picture mode
  • Call recording (if enabled)
  • Real-time chat during call
  • Participant list

Video Call Flow:

Patient requests call
    ↓
FCM push notification → OneToOneCallActivity
    ↓
Join meeting (VideoSDK token)
    ↓
WebRTC connection established
    ↓
Streaming starts

3. Patient Assessments

  • Location: CareProvider/Activities/InitialAssessmentAcitivity.java
  • Create custom questionnaires
  • Assign to patients
  • Review completed assessments
  • Track assessment history
  • Generate PDF reports

4. Homework Assignment

  • Location: CareProvider/Activities/NewHomeWorkActivity.java
  • Assign therapeutic exercises
  • Set due dates
  • Attach resources (PDFs, videos, links)
  • Track completion status
  • Review patient submissions
  • Provide feedback

5. Messaging

  • Location: CareProvider/Activities/ChatMainActivity.java, ConversationActivity.java
  • Real-time chat with patients
  • Send text, images, documents
  • Message history
  • Read receipts
  • Push notifications for new messages

6. Prescription Management

  • Location: views/activity/AddPrescriptionActivity.kt
  • Digital prescription creation
  • Drug database search
  • Dosage and duration management
  • E-signature
  • PDF export and sharing

7. Schedule Management

  • Location: CareProvider/Schedule/MarkAvailabiltyActivity.java
  • Define weekly availability
  • Set custom working hours
  • Block specific dates
  • Override availability for special days
  • Sync with booking system

8. Patient History

  • Location: CareProvider/Activities/ClientHistoryActivity.java
  • View complete patient timeline
  • Session notes
  • Diagnosis history
  • Treatment plans
  • Medications
  • Assessments and homework

9. Payments & Billing

  • Location: CareProvider/Activities/PaymentsDetailActivity.java
  • View payment history
  • Earnings breakdown
  • Payment status (pending, completed, refunded)
  • Export financial reports

10. Multi-language Support

  • Location: Stats/LocaleUtils.java, Stats/LangHelper.java
  • Arabic (RTL)
  • English (LTR)
  • Dynamic language switching
  • Persisted language preference

Architecture

Design Pattern: MVVM (Partial)

The app is in transition from traditional Android patterns to MVVM:

┌─────────────────┐
│     Activity    │ ← User interactions
│   /Fragment     │
└────────┬────────┘
         │
         ↓
┌─────────────────┐
│  Adapter/       │ ← Data binding (ViewBinding enabled)
│  ViewHolder     │
└────────┬────────┘
         │
         ↓
┌─────────────────┐
│  Data Models    │ ← POJOs (DataModels package)
│   (DTOs)        │
└────────┬────────┘
         │
         ↓
┌─────────────────┐
│  Network Layer  │ ← Fast Android Networking
│  (API Calls)    │
└────────┬────────┘
         │
         ↓
┌─────────────────┐
│  Backend API    │ ← REST endpoints
│  WebSocket      │ ← Real-time updates
└─────────────────┘

Key Architectural Components

1. Base Activities

  • BaseClientActivityMain.java: Main container activity with bottom navigation (5 tabs)
  • BaseCarePActivityMain.java: Legacy main activity (deprecated, use BaseClientActivityMain)

2. Navigation (Kotlin - Modern)

  • navigation/TabManager.kt: Manages NavigationController for bottom nav tabs
  • Uses Jetpack Navigation Component
  • Five tabs: Home, Appointments, Assessments, Homework, More

3. Network Layer

  • Library: Fast Android Networking (com.amitshekhar.android:android-networking)
  • Pattern: Direct API calls in Activities/Fragments (no repository pattern yet)
  • Authentication: Bearer token in headers

Example:

AndroidNetworking.get(Utils.BaseURL + "api/CareProvider/GetAppointments")
    .addHeaders("Authorization", "Bearer " + mpref.GetUserToken())
    .setPriority(Priority.MEDIUM)
    .build()
    .getAsJSONObject(new JSONObjectRequestListener() {
        @Override
        public void onResponse(JSONObject response) {
            // Handle success
        }
        @Override
        public void onError(ANError error) {
            // Handle error
        }
    });

4. Data Persistence

  • SharedPreferences: User session, tokens, settings (MySharedPreferences.java)
  • No local database: All data fetched from server on-demand
  • Cache: Glide for image caching

5. Event Bus

  • MessageObservable.java: Observer pattern for cross-component messaging
  • Used for: New messages, appointment updates, call state changes

6. Background Work

  • WorkManager: Periodic sync tasks (workers/ package)
  • Services:
  • MyFirebaseMessagingService: FCM handler
  • FloatingViewService: Picture-in-picture overlay
  • GetSlotsService: Appointment slot sync

Dependencies

Core Android

implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.fragment:fragment:1.6.2'
implementation 'androidx.navigation:navigation-fragment:2.5.0'
implementation 'androidx.navigation:navigation-ui:2.5.0'
implementation 'androidx.work:work-runtime:2.8.1'

Video SDK

implementation('live.videosdk:rtc-android-sdk:0.1.31') {
    exclude group: "com.google.android.material", module: "material"
}

Networking

implementation 'com.amitshekhar.android:android-networking:1.0.2'
implementation 'com.loopj.android:android-async-http:1.4.9'
implementation 'com.neovisionaries:nv-websocket-client:2.3'

Firebase

implementation 'com.google.firebase:firebase-messaging:23.4.0'
implementation 'com.google.firebase:firebase-auth:22.3.1'
implementation 'com.google.firebase:firebase-crashlytics:18.4.1'
implementation 'com.google.firebase:firebase-analytics:21.3.0'

UI Libraries

implementation 'com.github.bumptech.glide:glide:4.16.0'
implementation 'de.hdodenhof:circleimageview:2.1.0'
implementation 'com.squareup.picasso:picasso:2.4.0'
implementation 'com.airbnb.android:lottie:5.2.0'
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.22'
implementation 'com.github.GrenderG:Toasty:1.4.0'

Utilities

implementation 'com.google.code.gson:gson:2.8.5'
implementation 'nu.aaro.gustav:passwordstrengthmeter:0.4'
implementation 'com.intuit.sdp:sdp-android:1.0.6' // Scalable DP
implementation 'com.intuit.ssp:ssp-android:1.0.6' // Scalable SP

Custom Components

implementation project(':duo-navigation-drawer')   // Slide-out navigation
implementation project(':intlphoneinput')          // Phone input with country codes

Full dependency list

See app/build.gradle for complete list (50+ dependencies).


Firebase Integration

Firebase Cloud Messaging (FCM)

Configuration File: app/google-services.json

Handler: MyFirebaseMessagingService.java

Push Notification Types

Notification Type Action Intent Filter
New Message Open ChatMainActivity notificationType=1
Appointment Reminder Open MyAppointCarePFragment notificationType=2
Incoming Call Open OneToOneCallActivity notificationType=3
Assessment Assigned Open MyQyestionaireFragment notificationType=4
Homework Due Open MyHomeWorkFragment notificationType=5
Payment Received Open PaymentsDetailActivity notificationType=6

FCM Token Management

Token is sent to backend on:
- App installation
- Token refresh
- User login

// MyFirebaseMessagingService.java
@Override
public void onNewToken(String token) {
    // Send token to backend
    sendTokenToServer(token);
}

Firebase Crashlytics

Automatically captures crashes. Manual logging:

FirebaseCrashlytics.getInstance().log("User action: " + action);
FirebaseCrashlytics.getInstance().recordException(exception);

API Integration

Base URLs

Configured in Stats/Utils.java and Stats/MySharedPreferences.java:

Service URL Variable Purpose
Main API BaseURL Authentication, appointments, users
Documents BaseURLDocument Upload/download files
Video BaseURLVideo Video session metadata
Scheduling BaseURLScheduling Slot management (legacy)
Payment BaseURLPayment Payment processing (web redirect)
Wallet BaseURLAddWalletAmount Wallet top-up

Authentication

OAuth 2.0 with Bearer tokens.

Login Flow

1. POST /api/Auth/Login
   Body: { "email": "...", "password": "..." }

2. Response: {
     "access_token": "...",
     "refresh_token": "...",
     "expires_in": 3600,
     "user": { ... }
   }

3. Store tokens in SharedPreferences
   mpref.SetUserToken(access_token)
   mpref.SetRefreshToken(refresh_token)

4. Add to all API requests:
   .addHeaders("Authorization", "Bearer " + token)

Token Refresh

POST /api/Auth/RefreshToken
Body: { "refresh_token": "..." }

Response: { "access_token": "...", "expires_in": 3600 }

Common API Endpoints

Care Provider APIs

Endpoint Method Purpose
/api/CareProvider/GetAppointments GET List appointments
/api/CareProvider/GetPatientHistory GET Patient timeline
/api/CareProvider/CreateAssessment POST New assessment
/api/CareProvider/AssignHomework POST Assign homework
/api/CareProvider/GetMessages GET Chat history
/api/CareProvider/SendMessage POST Send message
/api/CareProvider/GetSchedule GET Provider schedule
/api/CareProvider/UpdateAvailability POST Modify schedule
/api/CareProvider/GetPayments GET Payment history

Messaging APIs

Endpoint Method Purpose
/api/Messaging/GetConversations GET Conversation list
/api/Messaging/GetMessages GET Messages in conversation
/api/Messaging/SendMessage POST Send text message
/api/Messaging/SendAttachment POST Send file
/api/Messaging/MarkAsRead POST Mark messages read

Assessment APIs

Endpoint Method Purpose
/api/Assessment/GetTemplates GET Assessment templates
/api/Assessment/CreateAssessment POST Assign to patient
/api/Assessment/GetResponses GET Patient responses
/api/Assessment/SubmitFeedback POST Provider feedback

Error Handling

Standard error response:

{
  "success": false,
  "message": "Error description",
  "errorCode": "ERR_CODE"
}

Common error codes:
- 401: Unauthorized (token expired)
- 403: Forbidden (insufficient permissions)
- 404: Not found
- 500: Server error


Video Call Implementation

Technology: VideoSDK

SDK Version: 0.1.31
Documentation: https://docs.videosdk.live/android/guide/video-and-audio-calling-api-sdk/quick-start

Architecture

OneToOneCallActivity.kt
    ↓
VideoSDK.initMeeting(context, meetingId, participantName, micEnabled, webcamEnabled, ...)
    ↓
Meeting object
    ↓
meeting.join()
    ↓
WebRTC connection established
    ↓
Participant streams (video/audio tracks)
    ↓
Rendered in VideoView

Meeting Flow

  1. Create/Join Meeting

    // OneToOneCallActivity.kt
    private fun joinMeeting() {
        val meeting = VideoSDK.initMeeting(
            this,
            meetingId,
            participantName,
            micEnabled = true,
            webcamEnabled = true,
            participantId = null,
            mode = "CONFERENCE",
            multiStream = true,
            customCameraVideoTrack = null,
            customMicrophoneAudioTrack = null,
            maxResolution = "hd"
        )
    
        meeting.addEventListener(meetingEventListener)
        meeting.join()
    }
    

  2. Event Listeners

    private val meetingEventListener = object : MeetingEventListener() {
        override fun onMeetingJoined() {
            // Meeting joined successfully
        }
    
        override fun onMeetingLeft() {
            // Meeting ended
            finish()
        }
    
        override fun onParticipantJoined(participant: Participant) {
            // Remote participant joined
            setupRemoteParticipant(participant)
        }
    
        override fun onParticipantLeft(participant: Participant) {
            // Remote participant left
        }
    }
    

  3. Video Rendering

    private fun setupRemoteParticipant(participant: Participant) {
        participant.addEventListener(object : ParticipantEventListener() {
            override fun onStreamEnabled(stream: Stream) {
                if (stream.kind == "video") {
                    val videoView = findViewById<VideoView>(R.id.participantVideoView)
                    val videoTrack = stream.track as VideoTrack
                    videoTrack.addSink(videoView)
                }
            }
        })
    }
    

Controls

Control Method Description
Mute/Unmute Mic meeting.muteMic() / unmuteMic() Toggle audio
Enable/Disable Cam meeting.disableWebcam() / enableWebcam() Toggle video
Switch Camera meeting.changeWebcam() Front/back
Leave Meeting meeting.leave() End call
Screen Share meeting.enableScreenShare() Share screen

Picture-in-Picture

// AndroidManifest.xml
<activity
    android:name=".CareProvider.Activities.OneToOneCallActivity"
    android:supportsPictureInPicture="true"
    android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" />

// OneToOneCallActivity.kt
private fun enterPipMode() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val params = PictureInPictureParams.Builder()
            .setAspectRatio(Rational(16, 9))
            .build()
        enterPictureInPictureMode(params)
    }
}

Legacy WebRTC (Deprecated)

Location: Collaboration/Presence/CollaborationMain.java

This is the older WebRTC implementation (Google WebRTC). Still present in codebase but being phased out in favor of VideoSDK.


Bottom Navigation (5 Tabs)

Managed by navigation/TabManager.kt and bottomnavbar/ components.

┌──────────────────────────────────────────┐
│  [Home] [Appts] [Tests] [HW] [More]      │
└──────────────────────────────────────────┘
Tab ID Fragment Navigation Graph
Home navigation_home HomeFragment nav_home.xml
Appointments navigation_appointments AppointmentsFragment nav_appointments.xml
Assessments navigation_assessment MyQyestionaireFragment nav_assessment.xml
Homework navigation_homeworks HomeworksFragment nav_homeworks.xml
More navigation_more MoreTabFragment nav_more.xml

Location: res/navigation/

Each tab has its own navigation graph for deep navigation:

<!-- nav_home.xml -->
<navigation>
    <fragment id="@+id/homeFragment" ... >
        <action id="@+id/action_home_to_profile" destination="@+id/profileFragment" />
        <action id="@+id/action_home_to_chat" destination="@+id/chatListFragment" />
    </fragment>
</navigation>

Tab Switching Logic

// TabManager.kt
fun switchTab(tabId: Int) {
    currentController = when (tabId) {
        R.id.navigation_home -> navHomeController
        R.id.navigation_appointments -> navAppointmentsController
        R.id.navigation_assessment -> navAssessmentController
        R.id.navigation_homeworks -> navHomeworksController
        R.id.navigation_more -> navMoreController
        else -> navHomeController
    }

    tabHistory.push(tabId)
    showTab(tabId)
}

Back Navigation

Implements custom back stack for tab history:

override fun onBackPressed() {
    if (tabHistory.size > 1) {
        tabHistory.pop()
        val previousTab = tabHistory.peek()
        switchTab(previousTab)
    } else {
        finish()
    }
}

Common Issues & Troubleshooting

Build Issues

1. Gradle Sync Failed

Error: Could not resolve all dependencies

Solution:

# Clear Gradle cache
./gradlew clean
./gradlew --stop

# In Android Studio
File  Invalidate Caches  Invalidate and Restart

2. NDK Not Found

Error: NDK is not configured

Solution:
1. Open SDK Manager → SDK Tools
2. Install NDK version 23.1.7779620
3. Add to local.properties:

ndk.dir=C\:\\Users\\<USER>\\AppData\\Local\\Android\\Sdk\\ndk\\23.1.7779620

3. Duplicate Class Error

Error: Duplicate class com.google.android.gms...

Solution: Check for conflicting Firebase versions. Align all Firebase dependencies to same version:

implementation platform('com.google.firebase:firebase-bom:31.0.0')
implementation 'com.google.firebase:firebase-messaging'
implementation 'com.google.firebase:firebase-crashlytics'

Runtime Issues

1. Firebase Not Working

Symptom: Push notifications not received

Diagnosis:

// Check FCM token
FirebaseMessaging.getInstance().getToken()
    .addOnCompleteListener(task -> {
        if (task.isSuccessful()) {
            String token = task.getResult();
            Log.d("FCM", "Token: " + token);
            // Verify token is sent to server
        }
    });

Solution:
- Verify google-services.json is present
- Check package name matches Firebase console
- Ensure Firebase services are enabled in console
- Verify internet permission is granted

2. Video Call Not Connecting

Symptom: Black screen or “Connection Failed”

Troubleshooting:
1. Check permissions (CAMERA, RECORD_AUDIO granted)
2. Verify VideoSDK token is valid
3. Check internet connectivity
4. Review logs for WebRTC errors:

adb logcat | grep -i "webrtc\|videosdk"

Common Causes:
- Firewall blocking WebRTC ports
- Invalid meeting ID
- Network behind symmetric NAT (needs TURN server)

3. App Crashes on Startup

Symptom: Immediate crash after splash screen

Diagnosis:

adb logcat | grep -i "androidruntime"

Common Causes:
- Missing permissions (Check AndroidManifest.xml)
- Null pointer in MainApplication.onCreate()
- Firebase initialization failure
- Network security config blocking HTTP

4. API Calls Failing (401 Unauthorized)

Symptom: All API requests return 401

Solution:

// Check token expiration
String token = mpref.GetUserToken();
if (token == null || token.isEmpty()) {
    // Redirect to login
    startActivity(new Intent(this, LoginActivity.class));
    finish();
}

// Try refreshing token
refreshAuthToken();

5. Images Not Loading

Symptom: Profile pictures or documents show placeholder

Diagnosis:

// Enable Glide logging
Glide.with(this)
    .load(imageUrl)
    .listener(new RequestListener<Drawable>() {
        @Override
        public boolean onLoadFailed(...) {
            Log.e("Glide", "Failed to load: " + imageUrl);
            return false;
        }
        @Override
        public boolean onResourceReady(...) {
            return false;
        }
    })
    .into(imageView);

Solution:
- Verify image URL is correct (check Utils.BaseURL)
- Check network security config allows domain
- Ensure READ_EXTERNAL_STORAGE permission granted

Performance Issues

1. Slow Appointment List Loading

Symptom: Long delay loading appointments

Optimization:

// Implement pagination
int page = 1;
int pageSize = 20;

AndroidNetworking.get(Utils.BaseURL + "api/CareProvider/GetAppointments")
    .addQueryParameter("page", String.valueOf(page))
    .addQueryParameter("pageSize", String.valueOf(pageSize))
    ...

2. Memory Leaks

Symptom: App becomes sluggish over time

Diagnosis: Use Android Profiler or LeakCanary

Common Causes:
- Static references to Activities/Fragments
- Unregistered BroadcastReceivers
- Unremoved callbacks

Prevention:

@Override
protected void onDestroy() {
    super.onDestroy();
    // Unregister receivers
    unregisterReceiver(networkReceiver);
    // Cancel network requests
    AndroidNetworking.cancel(this);
    // Clear references
    adapter = null;
}

Debug Tools

Enable Debug Logging

// Stats/Utils.java
public static boolean DEBUG_MODE = true;

// Throughout app
if (Utils.DEBUG_MODE) {
    Log.d("TAG", "Debug info: " + data);
}

Network Traffic Monitoring

# Use Charles Proxy or Android Studio Network Profiler
# Or adb command:
adb shell am start -n com.psyter.www/.Registration.Activities.SplashActivity
adb logcat | grep -i "okhttp\|networking"

Database Inspection (if using Room/SQLite)

adb shell
run-as com.psyter.www.careprovider
cd databases
sqlite3 database_name.db
.tables

Testing

Unit Testing

Framework: JUnit 4

Location: app/src/test/java/

Run tests:

./gradlew test

Example:

@Test
public void testPasswordValidation() {
    String password = "Test123!";
    assertTrue(Utils.isValidPassword(password));
}

Instrumented Testing

Framework: Espresso, AndroidX Test

Location: app/src/androidTest/java/

Run on device:

./gradlew connectedAndroidTest

Example:

@Test
public void testLoginFlow() {
    onView(withId(R.id.emailEditText))
        .perform(typeText("test@example.com"));

    onView(withId(R.id.passwordEditText))
        .perform(typeText("password123"));

    onView(withId(R.id.loginButton))
        .perform(click());

    onView(withId(R.id.homeFragment))
        .check(matches(isDisplayed()));
}

Manual Testing Checklist

  • Login with valid credentials
  • Login with invalid credentials (error shown)
  • View appointment list
  • Join video call (if test meeting available)
  • Send message to patient
  • Create assessment
  • Assign homework
  • Update schedule/availability
  • View payment history
  • Switch language (AR/EN)
  • Logout

Release Process

Pre-release Checklist

  • Update versionCode and versionName in app/build.gradle
  • Enable ProGuard (minifyEnabled true)
  • Test release build on physical devices
  • Verify all API endpoints point to production
  • Update google-services.json for production Firebase
  • Generate signed APK/AAB with release keystore
  • Run lint and fix critical issues: ./gradlew lint
  • Test in-app payments (if applicable)
  • Verify deep links work
  • Update CHANGELOG.md

Version Numbering

versionName: MAJOR.MINOR.PATCH
versionCode: Incremental integer

Example:
versionName "2.0.33"
versionCode 68

Creating Release Build

# 1. Clean project
./gradlew clean

# 2. Build release AAB (for Play Store)
./gradlew bundleCareProviderRelease

# 3. Output location
# app/build/outputs/bundle/careproviderRelease/app-careprovider-release.aab

# 4. Test AAB with bundletool
java -jar bundletool.jar build-apks \
  --bundle=app-careprovider-release.aab \
  --output=app.apks \
  --mode=universal

# 5. Install on device
java -jar bundletool.jar install-apks --apks=app.apks

Play Store Submission

  1. Prepare assets:
    - App icon (512x512 PNG)
    - Feature graphic (1024x500 PNG)
    - Screenshots (4-8 screenshots, 16:9 or 9:16)
    - Privacy policy URL
    - App description (EN, AR)

  2. Upload AAB to Play Console

  3. Fill out store listing
  4. Set pricing & distribution
  5. Submit for review

Contributing Guidelines

Code Style

Java:
- Follow Android/Google Java Style Guide
- Use meaningful variable names
- Maximum line length: 120 characters
- Indentation: 4 spaces

Kotlin:
- Follow Kotlin Coding Conventions
- Use data classes for models
- Prefer val over var
- Use extension functions for utilities

Git Workflow

Branch naming:

feature/feature-name
bugfix/bug-description
hotfix/critical-fix

Commit messages:

feat: Add prescription PDF export
fix: Resolve video call crash on Android 13
refactor: Extract networking logic to repository
docs: Update setup instructions

Pull Request Process

  1. Create feature branch from develop
  2. Make changes with clear commits
  3. Update documentation if needed
  4. Test thoroughly
  5. Create PR with description of changes
  6. Request code review
  7. Address review comments
  8. Merge after approval

Code Review Checklist

  • Code follows style guidelines
  • No hardcoded strings (use strings.xml)
  • No hardcoded URLs/credentials
  • Proper error handling
  • Memory leaks addressed
  • No excessive logging in release builds
  • UI tested on multiple screen sizes
  • Accessibility attributes added
  • Permissions requested at runtime

Additional Resources

Documentation

Tools

Internal Resources

  • Backend API Documentation: (Link to internal docs)
  • Design System: (Link to Figma/design resources)
  • Slack Channel: #android-dev
  • JIRA Board: (Link to project board)

Support

Getting Help

  • Technical Issues: Create issue in repository or contact Android team
  • API Questions: Contact backend team
  • Design Questions: Contact UX team
  • Security Concerns: Email security@psyter.com

Reporting Bugs

When reporting bugs, include:
1. Device information: Model, Android version
2. App version: versionName and versionCode
3. Steps to reproduce
4. Expected vs. actual behavior
5. Logs: adb logcat output
6. Screenshots/screen recordings


Document Maintained By: Android Development Team
Last Updated: November 2025
Version: 1.0


Appendix

A. Common Utility Methods

// Stats/Utils.java

// Check internet connectivity
public static boolean isInternetAvailable(Context context) {
    ConnectivityManager cm = (ConnectivityManager) 
        context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}

// Show toast message
public static void showToast(Context context, String message) {
    Toasty.success(context, message, Toast.LENGTH_SHORT).show();
}

// Format date
public static String formatDate(String isoDate) {
    SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
    SimpleDateFormat outputFormat = new SimpleDateFormat("dd MMM yyyy", Locale.US);
    try {
        Date date = inputFormat.parse(isoDate);
        return outputFormat.format(date);
    } catch (ParseException e) {
        return isoDate;
    }
}

B. SharedPreferences Keys

// MySharedPreferences.java

// Authentication
"UserToken"           // JWT access token
"RefreshToken"        // OAuth refresh token
"UserID"              // User ID
"UserEmail"           // User email
"UserRole"            // User role (CareProvider, Client)

// Settings
"Language"            // "en" or "ar"
"NotificationsEnabled" // boolean
"Theme"               // "light" or "dark"

// Session
"IsLoggedIn"          // boolean
"LastSyncTime"        // timestamp
"FCMToken"            // Firebase token

// URLs (can be updated remotely)
"BaseURL"
"BaseURLDocument"
"BaseURLVideo"
"BaseURLScheduling"

C. Error Codes Reference

Code Message Action
1000 Invalid credentials Show login error
1001 Token expired Refresh token
1002 Account suspended Show contact support message
2000 Network error Retry request
2001 Timeout Show timeout message
3000 Validation error Show field error
4000 Resource not found Show not found message
5000 Server error Show generic error

This enhanced README provides comprehensive documentation for the AndroidCareProvider application. For questions or updates, contact the Android development team.