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¶
- Overview
- Prerequisites
- Project Structure
- Setup Instructions
- Configuration
- Building the Application
- Key Features
- Architecture
- Dependencies
- Firebase Integration
- API Integration
- Video Call Implementation
- Navigation Structure
- Common Issues & Troubleshooting
- Testing
- Release Process
- 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¶
- Android Studio: Arctic Fox (2020.3.1) or later (recommended: Latest stable)
- JDK: Java Development Kit 8 or 11
- Android SDK:
- SDK Platform 33 (Android 13)
- Build Tools 33.x.x
- Android SDK Platform-Tools
- Android SDK Command-line Tools - Git: For version control
- 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¶
- Launch Android Studio
- Select File → Open
- Navigate to
Psyter/AndroidCareProvider - Click OK
- Wait for Gradle sync to complete
3. Configure Firebase¶
Option A: Use Existing Configuration¶
The repository includes google-services.json (dev environment). For production:
- Obtain the production
google-services.jsonfrom Firebase Console - Replace
app/google-services.json - Sync Gradle
Option B: Set Up New Firebase Project¶
- Go to Firebase Console
- Create new project or select existing
- Add Android app:
- Package name:com.psyter.www.careprovider
- App nickname: Psyter Care Provider
- Debug signing certificate: (optional for development) - Download
google-services.json - Place in
app/directory - Enable Firebase Cloud Messaging (FCM)
- 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:
- Open Tools → SDK Manager
- Navigate to SDK Tools tab
- Check NDK (Side by side) - version 23.1.7779620
- 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 handlerFloatingViewService: Picture-in-picture overlayGetSlotsService: 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¶
-
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() } -
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 } } -
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.
Navigation Structure¶
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 |
Navigation Graphs¶
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
versionCodeandversionNameinapp/build.gradle - Enable ProGuard (
minifyEnabled true) - Test release build on physical devices
- Verify all API endpoints point to production
- Update
google-services.jsonfor 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¶
-
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) -
Upload AAB to Play Console
- Fill out store listing
- Set pricing & distribution
- 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¶
- Create feature branch from
develop - Make changes with clear commits
- Update documentation if needed
- Test thoroughly
- Create PR with description of changes
- Request code review
- Address review comments
- 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¶
- Android Studio: https://developer.android.com/studio
- Charles Proxy: https://www.charlesproxy.com/ (network debugging)
- LeakCanary: https://square.github.io/leakcanary/ (memory leak detection)
- Postman: https://www.postman.com/ (API testing)
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.