Skip to content

Commit

Permalink
Merge branch 'develop' into fix/failed-image-messages-not-visible-che…
Browse files Browse the repository at this point in the history
…rry-pick
  • Loading branch information
ohassine authored Oct 24, 2024
2 parents ce304da + 46d80bb commit 34ef67e
Show file tree
Hide file tree
Showing 93 changed files with 2,051 additions and 244 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
app/src/internalDebug/screenshotTests/** filter=lfs diff=lfs merge=lfs -text
107 changes: 107 additions & 0 deletions .github/workflows/generate-screenshots.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: "Generate and Verify Screenshot Tests"

on:
workflow_dispatch:

permissions:
contents: write
pull-requests: write

env:
GITHUB_TOKEN: ${{ secrets.ANDROID_BOB_GH_TOKEN }}

jobs:
generate-screenshots:
runs-on: buildjet-8vcpu-ubuntu-2204

if: github.ref == 'refs/heads/develop'

steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0

- name: Set up JDK 17
uses: buildjet/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: gradle

- name: Validate Gradle wrapper
uses: gradle/actions/wrapper-validation@v4

- name: Install Git LFS
run: |
git lfs install
git lfs fetch --all
git lfs checkout
- name: Merge Develop into screenshot-tests
run: |
git checkout screenshot-tests
git merge origin/develop --no-edit
git push origin screenshot-tests
- name: Verify Screenshot Tests
run: ./gradlew validateInternalDebugScreenshotTest
continue-on-error: true # Ensure this task doesn't fail the build

- name: Copy test results to simplified directory
run: |
mkdir -p screenshotTest
cp -r app/build/reports/screenshotTest/preview/debug/internal/* screenshotTest/
- name: Zip Screenshot Test Reports
run: |
zip -r screenshot-test-report.zip screenshotTest/
- name: Upload Screenshot Test Report
id: upload_artifact
uses: actions/upload-artifact@v4
with:
name: screenshot-test-report
path: screenshot-test-report.zip

- name: Clear changes before generating new screenshots
run: |
git reset --hard HEAD
git clean -fd
- name: Update Screenshot Reference Images
run: ./gradlew updateInternalDebugScreenshotTest

- name: Setup GitHub Actions Bot for Git
uses: fregante/setup-git-user@v2

- name: Create New Branch
id: create_branch
run: |
BRANCH_NAME="test/screenshots-update-$(date +%Y%m%d%H%M%S)"
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
git checkout -b "$BRANCH_NAME"
git add .
git commit -m "test: update screenshot tests"
git push origin "$BRANCH_NAME"
- name: Create PR
env:
PR_TITLE: "test: Update Screenshot Tests [WPB-983]"
PR_BODY: "Automated PR to update screenshot tests with the latest reference images."
PR_BRANCH: ${{ env.BRANCH_NAME }}
run: |
gh pr create --title "$PR_TITLE" --body "$PR_BODY" --base screenshot-tests --head "$PR_BRANCH" --label "screenshot-test"
PR_NUMBER=$(gh pr view --json number -q .number)
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
- name: Add comment with test report link
run: |
ARTIFACT_ID=${{ steps.upload_artifact.outputs.artifact-id }}
gh issue comment "${{ env.PR_NUMBER }}" --body "Screenshot test results have been generated. [Download the report](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts/$ARTIFACT_ID)"
- name: Cleanup Gradle Cache
run: |
rm -f ~/.gradle/caches/modules-2/modules-2.lock
rm -f ~/.gradle/caches/modules-2/gc.properties
11 changes: 11 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ plugins {
id(ScriptPlugins.testing)
id(libs.plugins.wire.kover.get().pluginId)
id(libs.plugins.wire.versionizer.get().pluginId)
alias(libs.plugins.screenshot)
}

repositories {
Expand Down Expand Up @@ -82,6 +83,13 @@ android {
jniLibs.pickFirsts.add("**/libsodium.so")
}
android.buildFeatures.buildConfig = true
experimentalProperties["android.experimental.enableScreenshotTest"] = true

testOptions {
screenshotTests {
imageDifferenceThreshold = 0.0001f // 0.01%
}
}

sourceSets {
allFlavors.forEach { flavor ->
Expand Down Expand Up @@ -240,6 +248,9 @@ dependencies {
implementation(libs.aboutLibraries.ui)
implementation(libs.compose.qr.code)

// screenshot testing
screenshotTestImplementation(libs.compose.ui.tooling)

// Unit/Android tests dependencies
testImplementation(libs.androidx.test.archCore)
testImplementation(libs.junit4) // Maybe migrate completely to Junit 5?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,17 @@

package com.wire.android.feature

import android.content.Context
import android.content.Intent
import android.os.Build
import com.wire.android.appLogger
import com.wire.android.services.PersistentWebSocketService
import dagger.hilt.android.qualifiers.ApplicationContext
import com.wire.android.services.ServicesManager
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class StartPersistentWebsocketIfNecessaryUseCase @Inject constructor(
@ApplicationContext private val appContext: Context,
private val servicesManager: ServicesManager,
private val shouldStartPersistentWebSocketService: ShouldStartPersistentWebSocketServiceUseCase
) {
suspend operator fun invoke() {
val persistentWebSocketServiceIntent = PersistentWebSocketService.newIntent(appContext)
shouldStartPersistentWebSocketService().let {
when (it) {
is ShouldStartPersistentWebSocketServiceUseCase.Result.Failure -> {
Expand All @@ -43,33 +38,17 @@ class StartPersistentWebsocketIfNecessaryUseCase @Inject constructor(

is ShouldStartPersistentWebSocketServiceUseCase.Result.Success -> {
if (it.shouldStartPersistentWebSocketService) {
startForegroundService(persistentWebSocketServiceIntent)
appLogger.i("${TAG}: Starting PersistentWebsocketService")
servicesManager.startPersistentWebSocketService()
} else {
appLogger.i("${TAG}: Stopping PersistentWebsocketService, no user with persistent web socket enabled found")
appContext.stopService(persistentWebSocketServiceIntent)
servicesManager.stopPersistentWebSocketService()
}
}
}
}
}

private fun startForegroundService(persistentWebSocketServiceIntent: Intent) {
when {
PersistentWebSocketService.isServiceStarted -> {
appLogger.i("${TAG}: PersistentWebsocketService already started, not starting again")
}

else -> {
appLogger.i("${TAG}: Starting PersistentWebsocketService")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
appContext.startForegroundService(persistentWebSocketServiceIntent)
} else {
appContext.startService(persistentWebSocketServiceIntent)
}
}
}
}

companion object {
const val TAG = "StartPersistentWebsocketIfNecessaryUseCase"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ object ReportBugDestination : IntentDirection {
val dir = LogFileWriter.logsDirectory(context)
val logsUris = context.getUrisOfFilesInDirectory(dir)
val intent = context.multipleFileSharingIntent(logsUris)
intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("[email protected]"))
intent.putExtra(Intent.EXTRA_SUBJECT, "Bug Report - Wire Beta")
intent.putExtra(Intent.EXTRA_EMAIL, arrayOf(context.getString(R.string.send_bug_report_email)))
intent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.send_bug_report_subject))
intent.putExtra(
Intent.EXTRA_TEXT,
EmailComposer.reportBugEmailTemplate(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.navigation

import com.ramcosta.composedestinations.spec.Direction
import com.wire.android.ui.destinations.TeamMigrationConfirmationStepScreenDestination
import com.wire.android.ui.destinations.TeamMigrationDoneStepScreenDestination

sealed class TeamMigrationDestination(
val direction: Direction
) {

data object Confirmation : TeamMigrationDestination(
direction = TeamMigrationConfirmationStepScreenDestination
)

data object MigrationDone : TeamMigrationDestination(
direction = TeamMigrationDoneStepScreenDestination
)

val itemName: String get() = ITEM_NAME_PREFIX + this

companion object {
private const val ITEM_NAME_PREFIX = "TeamMigrationNavigationItem."
fun fromRoute(fullRoute: String): TeamMigrationDestination? =
values().find { it.direction.route.getBaseRoute() == fullRoute.getBaseRoute() }

fun values(): Array<TeamMigrationDestination> =
arrayOf(Confirmation, MigrationDone)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@

package com.wire.android.services

import android.app.ForegroundServiceStartNotAllowedException
import android.app.Notification
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.app.ServiceCompat
Expand Down Expand Up @@ -131,12 +133,29 @@ class PersistentWebSocketService : Service() {
.setOngoing(true)
.build()

ServiceCompat.startForeground(
this,
NotificationIds.PERSISTENT_NOTIFICATION_ID.ordinal,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
try {
ServiceCompat.startForeground(
this,
NotificationIds.PERSISTENT_NOTIFICATION_ID.ordinal,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
)
} catch (e: ForegroundServiceStartNotAllowedException) {
// ForegroundServiceStartNotAllowedException may be thrown on restarting service from the background.
// this is the only suggested workaround from google for now.
// https://issuetracker.google.com/issues/307329994#comment86
appLogger.e("Failure while starting foreground: $e")
stopSelf()
}
} else {
ServiceCompat.startForeground(
this,
NotificationIds.PERSISTENT_NOTIFICATION_ID.ordinal,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
)
}
}

override fun onDestroy() {
Expand Down
15 changes: 9 additions & 6 deletions app/src/main/kotlin/com/wire/android/services/ServicesManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

package com.wire.android.services

import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
Expand All @@ -34,7 +33,6 @@ import kotlinx.coroutines.launch
import org.jetbrains.annotations.VisibleForTesting
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.reflect.KClass

/**
* This is helper class that should be used for starting/stopping any services.
Expand Down Expand Up @@ -102,11 +100,15 @@ class ServicesManager @Inject constructor(

// Persistent WebSocket
fun startPersistentWebSocketService() {
startService(PersistentWebSocketService.newIntent(context))
if (PersistentWebSocketService.isServiceStarted) {
appLogger.i("ServicesManager: PersistentWebsocketService already started, not starting again")
} else {
startService(PersistentWebSocketService.newIntent(context))
}
}

fun stopPersistentWebSocketService() {
stopService(PersistentWebSocketService::class)
stopService(PersistentWebSocketService.newIntent(context))
}

fun isPersistentWebSocketServiceRunning(): Boolean =
Expand All @@ -121,8 +123,9 @@ class ServicesManager @Inject constructor(
}
}

private fun stopService(serviceClass: KClass<out Service>) {
context.stopService(Intent(context, serviceClass.java))
private fun stopService(intent: Intent) {
appLogger.i("ServicesManager: stopping service for $intent")
context.stopService(intent)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ private fun RegisterDeviceContent(
WireCenterAlignedTopAppBar(
elevation = dimensions().spacing0x,
title = stringResource(id = R.string.register_device_title),
navigationIconType = NavigationIconType.Close,
navigationIconType = NavigationIconType.Close(),
onNavigationPressed = onBackButtonClicked
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fun RemoveDeviceTopBar(elevation: Dp, onBackButtonClicked: () -> Unit) {
WireCenterAlignedTopAppBar(
elevation = elevation,
title = stringResource(R.string.remove_device_title),
navigationIconType = NavigationIconType.Close,
navigationIconType = NavigationIconType.Close(),
onNavigationPressed = onBackButtonClicked
) {
Text(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ private fun WelcomeContent(
WireCenterAlignedTopAppBar(
elevation = dimensions().spacing0x,
title = "",
navigationIconType = NavigationIconType.Close,
navigationIconType = NavigationIconType.Close(),
onNavigationPressed = navigateBack
)
} else {
Expand Down
Loading

0 comments on commit 34ef67e

Please sign in to comment.