Skip to content

Commit

Permalink
Updates test app to have more functionality so we can verify multiple… (
Browse files Browse the repository at this point in the history
#5481)

… processes and crash behaviour with the SDK.
  • Loading branch information
bryanatkinson authored Oct 30, 2023
1 parent b78b7ea commit d9bdc42
Show file tree
Hide file tree
Showing 26 changed files with 1,021 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.google.firebase.testing.sessions

import androidx.lifecycle.Lifecycle.State
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
Expand Down Expand Up @@ -49,18 +50,28 @@ class FirebaseSessionsTest {
FirebaseSessionsDependencies.register(fakeSessionSubscriber)

ActivityScenario.launch(MainActivity::class.java).use { scenario ->
scenario.onActivity {
// Wait for the settings to be fetched from the server.
Thread.sleep(TIME_TO_READ_SETTINGS)
}
// Move the activity to the background and then foreground
// This is necessary because the initial app launch does not yet know whether the sdk is
// enabled, and so the first session isnt' created until a lifecycle event happens after the
// settings are read.
scenario.moveToState(State.CREATED)
scenario.moveToState(State.RESUMED)
scenario.onActivity {
// Wait for the session start event to send.
Thread.sleep(TIME_TO_LOG_SESSION)

// Assert that some session was generated and sent to the subscriber.
assertThat(fakeSessionSubscriber.sessionDetails).isNotNull()
}
}
}

companion object {
private const val TIME_TO_LOG_SESSION = 60_000L
private const val TIME_TO_READ_SETTINGS = 60_000L
private const val TIME_TO_LOG_SESSION = 10_000L

init {
FirebaseSessionsDependencies.addDependency(SessionSubscriber.Name.MATT_SAYS_HI)
Expand Down
94 changes: 73 additions & 21 deletions firebase-sessions/test-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,23 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application
android:allowBackup="true"
android:icon="@drawable/sensor_window"
android:label="@string/app_name"
android:name="androidx.multidex.MultiDexApplication"
android:supportsRtl="true"
android:theme="@style/Theme.TestApp">
<activity
android:exported="true"
android:name=".MainActivity"
android:theme="@style/Theme.TestApp.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2023 Google LLC
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>

<application
android:name=".TestApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Widget_test_app"
tools:targetApi="31">
<meta-data
android:name="firebase_performance_logcat_enabled"
android:value="true" />
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Widget_test_app.NoActionBar"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity
android:name=".SecondActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Widget_test_app.NoActionBar"
android:process=":second"/>

<receiver
android:name="CrashWidgetProvider"
android:process=":widgetProcess"
android:exported="false">
<intent-filter>
<action
android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/homescreen_widget" />
</receiver>

<receiver android:name=".CrashBroadcastReceiver" />

<service
android:name=".ForegroundService"
android:process=":foregroundServiceProcess"
android:enabled="true"
android:exported="false" />

</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.firebase.testing.sessions

import android.app.ActivityManager
import android.app.ActivityManager.RunningAppProcessInfo
import android.app.Application
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.google.firebase.FirebaseApp

/** */
open class BaseActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
FirebaseApp.initializeApp(this)
Log.i(TAG, "onCreate - ${getProcessName()} - ${getImportance()}")
}

override fun onPause() {
super.onPause()
Log.i(TAG, "onPause - ${getProcessName()} - ${getImportance()}")
}

override fun onStop() {
super.onStop()
Log.i(TAG, "onStop - ${getProcessName()} - ${getImportance()}")
}

override fun onResume() {
super.onResume()
Log.i(TAG, "onResume - ${getProcessName()} - ${getImportance()}")
}

override fun onStart() {
super.onStart()
Log.i(TAG, "onStart - ${getProcessName()} - ${getImportance()}")
}

override fun onDestroy() {
super.onDestroy()
Log.i(TAG, "onDestroy - ${getProcessName()} - ${getImportance()}")
}

private fun getImportance(): Int {
val processInfo = RunningAppProcessInfo()
ActivityManager.getMyMemoryState(processInfo)
return processInfo.importance
}

private fun getProcessName(): String = Application.getProcessName()

companion object {
val TAG = "BaseActivity"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.firebase.testing.sessions

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import android.widget.Toast

class CrashBroadcastReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {
Log.i(TAG, "Received intent: $intent")
when (intent.action) {
CRASH_ACTION -> crash(context)
TOAST_ACTION -> toast(context)
}
}

fun crash(context: Context) {
Toast.makeText(context, "KABOOM!", Toast.LENGTH_LONG).show()
throw RuntimeException("CRASH_BROADCAST")
}

fun toast(context: Context) {
Toast.makeText(context, "Cheers!", Toast.LENGTH_LONG).show()
}

companion object {
val TAG = "CrashBroadcastReceiver"
val CRASH_ACTION = "com.google.firebase.testing.sessions.CrashBroadcastReceiver.CRASH_ACTION"
val TOAST_ACTION = "com.google.firebase.testing.sessions.CrashBroadcastReceiver.TOAST_ACTION"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.firebase.testing.sessions

import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.icu.text.SimpleDateFormat
import android.widget.RemoteViews
import com.google.firebase.FirebaseApp
import java.util.Date
import java.util.Locale

/** Provides homescreen widget for the test app. */
class CrashWidgetProvider : AppWidgetProvider() {

override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
FirebaseApp.initializeApp(context)

appWidgetIds.forEach { appWidgetId ->
// Get the layout for the widget and attach an on-click listener
// to the button.
val views: RemoteViews =
RemoteViews(context.packageName, R.layout.crash_widget).apply {
setOnClickPendingIntent(R.id.widgetCrashButton, getPendingCrashIntent(context))
setTextViewText(R.id.widgetTimeText, DATE_FMT.format(Date()))
}

// Tell the AppWidgetManager to perform an update on the current
// widget.
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}

override fun onReceive(context: Context, intent: Intent): Unit {
super.onReceive(context, intent)

if (CRASH_BUTTON_CLICK == intent.getAction()) {
throw RuntimeException("CRASHED FROM WIDGET")
}
}

fun getPendingCrashIntent(context: Context): PendingIntent {
val intent = Intent(context, CrashWidgetProvider::class.java)
intent.setAction(CRASH_BUTTON_CLICK)
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
}

companion object {
val CRASH_BUTTON_CLICK = "widgetCrashButtonClick"
val DATE_FMT = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
}
}
Loading

0 comments on commit d9bdc42

Please sign in to comment.