Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

staging -> main (Core 3.0.1/ Lifecycle 3.0.1/ Identity 3.0.1) #673

Merged
merged 42 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
511ba84
Fix IAM scrolling
prudrabhat Apr 3, 2024
7c05409
Remove unused parameters
prudrabhat Apr 3, 2024
843cb75
Move gesture detection to the CardView
prudrabhat Apr 11, 2024
ce3fdc5
Fix event history logs
praveek Apr 12, 2024
93c03d1
Update MapExtensions.kt
GeorgCantor Apr 14, 2024
fcfe48f
Update SetExtensions.kt
GeorgCantor Apr 14, 2024
fb54ac6
Update LaunchRuleTransformer.kt
GeorgCantor Apr 14, 2024
0f7ba19
Merge pull request #646 from GeorgCantor/patch-2
prudrabhat Apr 25, 2024
ad53037
Merge pull request #647 from GeorgCantor/patch-3
prudrabhat Apr 25, 2024
beb0791
Fix logs
praveek Apr 25, 2024
254b406
Merge pull request #643 from praveek/dev
praveek Apr 25, 2024
0299619
Update MapExtensions.kt
GeorgCantor Apr 26, 2024
c19a0d8
Notify PresentationDelegate on all webview uri's
prudrabhat May 6, 2024
a7764d8
Add a supervisorjob and exception hander to UIService
prudrabhat May 6, 2024
330dd07
mainScope need not be protected
prudrabhat May 7, 2024
7490508
Always recompute screen size related calculations
prudrabhat May 8, 2024
773da1f
Merge pull request #640 from prudrabhat/fix_iam_scrolling
prudrabhat May 13, 2024
774df76
Merge pull request #651 from prudrabhat/presentation_delegate_notific…
prudrabhat May 13, 2024
542e40d
Add UiAutomator dependancy + restricted config activity
prudrabhat May 13, 2024
c475ad9
Merge remote-tracking branch 'upstream/dev' into iam_resize
prudrabhat May 13, 2024
55b4059
Add screen rotation tests
prudrabhat May 13, 2024
91292ea
Fix formatting
prudrabhat May 13, 2024
ab819d9
Merge pull request #654 from prudrabhat/iam_resize
prudrabhat May 13, 2024
d01ca50
Add tests to verify AnalyticsForIdentityRequest event
kevinlind May 14, 2024
da77bf7
On opt-out clear push ID and flags but don't call updatePushIdentifer…
kevinlind May 14, 2024
165a9ad
Update tests to assert persisted push token
kevinlind May 14, 2024
efbd900
Remove timeout from functional tests which don't wait on async operat…
kevinlind May 15, 2024
4174358
Lifecycle v2 enhancement (app upgrade) (#650)
yangyansong-adbe May 15, 2024
f332b82
Update MapExtensions.kt
GeorgCantor May 15, 2024
b242087
Merge pull request #644 from GeorgCantor/patch-1
praveek May 15, 2024
1a7506e
Merge pull request #652 from prudrabhat/uiservice_errorhandling
praveek May 15, 2024
4e540fe
Clear analytics push sync flag when processing reset identities and p…
kevinlind May 17, 2024
873e81b
Add unit tests to verify reset identities and privacy opt-out clears …
kevinlind May 17, 2024
173d1df
Remove unused 'pushEnabled' variable from Identity
kevinlind May 17, 2024
476cea1
Consolidate calls to 'isPushEnabled' to reduce I/O reads
kevinlind May 17, 2024
7de156b
Use mutex when updating persisted push enabled flag.
kevinlind May 17, 2024
d6e91e9
Fix formatting in IdentityExtension
kevinlind May 17, 2024
e2563e0
Merge pull request #663 from kevinlind/mob-20855-push-event
praveek May 17, 2024
e550425
Catch exceptions when retrieving data from Activity (#669)
yangyansong-adbe May 23, 2024
bc08e97
Update versions [Core-3.0.1] [Identity-3.0.1] [Lifecycle-3.0.1]
praveek May 23, 2024
f1a544e
Merge pull request #672 from adobe/create-pull-request/patch
praveek May 23, 2024
6b49406
Merge pull request #670 from adobe/dev
yangyansong-adbe May 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions code/core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ dependencies {
implementation(BuildConstants.Dependencies.ANDROIDX_LIFECYCLE_KTX)

androidTestImplementation(BuildConstants.Dependencies.MOCKITO_CORE)
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0")
//TODO: Consider moving this to the aep-library plugin later
androidTestImplementation("com.linkedin.dexmaker:dexmaker-mockito-inline:2.28.3")
}
4 changes: 4 additions & 0 deletions code/core/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
<application>
<meta-data android:name="DeviceInfoServiceTests.testGetPropertyFromManifest.do.not.delete" android:value="this_is_a_value"/>
<activity android:name="com.adobe.marketing.mobile.internal.DataMarshallerTests$TestActivity" />
<activity
android:name="com.adobe.marketing.mobile.services.ui.RestrictedConfigActivity"
android:configChanges="orientation|screenSize"
/>
</application>
<uses-permission android:name="android.permission.INTERNET" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.io.Serializable

@RunWith(AndroidJUnit4::class)
class DataMarshallerTests {
Expand Down Expand Up @@ -176,6 +177,23 @@ class DataMarshallerTests {

@Test
fun marshalInvalidUrl_NoCrash() {
val throwsException = ObjectThrowsOnToString()
val intent =
Intent(ApplicationProvider.getApplicationContext(), TestActivity::class.java).apply {
putExtra("key", "value")
putExtra("exceptionKey", throwsException)
}

val activity = activityTestRule.launchActivity(intent)
val result = DataMarshaller.marshal(activity)
assertEquals(
mapOf("key" to "value"),
result
)
}

@Test
fun marshal_whenBundleThrowException_NoCrash() {
val intent =
Intent(ApplicationProvider.getApplicationContext(), TestActivity::class.java).apply {
data = Uri.parse("abc:abc")
Expand All @@ -188,7 +206,11 @@ class DataMarshallerTests {
result
)
}

private class ObjectThrowsOnToString : Serializable {
override fun toString(): String {
throw IllegalStateException("This is a test exception")
}
}
companion object {
const val LEGACY_PUSH_MESSAGE_ID = "adb_m_id"
const val PUSH_MESSAGE_ID_KEY = "pushmessageid"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
Copyright 2024 Adobe. All rights reserved.
This file is licensed to you 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 REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/

package com.adobe.marketing.mobile.services.ui

import androidx.activity.ComponentActivity

class RestrictedConfigActivity : ComponentActivity()
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
/*
Copyright 2024 Adobe. All rights reserved.
This file is licensed to you 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 REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/

package com.adobe.marketing.mobile.services.ui.message.views

import android.view.View
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.test.getUnclippedBoundsInRoot
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.adobe.marketing.mobile.services.ui.RestrictedConfigActivity
import com.adobe.marketing.mobile.services.ui.common.PresentationStateManager
import com.adobe.marketing.mobile.services.ui.message.InAppMessageSettings
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

/**
* AEPPresentable handles the orientation changes of a presentable by detaching and reattaching
* the presentable from the activity by listening to Application.ActivityLifecycleCallbacks.
* However, the test cannot be isolated to listen to ApplicationLifecycle changes at the screen level.
* So, the tests in this class are done on the MessageScreen which is attached to an activity that
* restricts orientation/screen size changes. So the rotation will not destroy the activity but it
* is expected that the MessageScreen will be recomposed to fit the new screen dimensions.
* While this is not the ideal test, it is the best we can do to test the
* orientation changes of the message screen along with [MessageScreenTests.testMessageScreenIsRestoredOnConfigurationChange]
* which tests the configuration changes of the message screen.
*/
@RunWith(AndroidJUnit4::class)
class MessageScreenOrientationTests {
@get: Rule
val composeTestRule = createAndroidComposeRule<RestrictedConfigActivity>()

private var onCreatedCalled = false
private var onDisposedCalled = false
private var onBackPressed = false
private val detectedGestures = mutableListOf<InAppMessageSettings.MessageGesture>()
private val presentationStateManager = PresentationStateManager()

private val HTML_TEXT_SAMPLE = "<html>\n" +
"<head>\n" +
"<title>A Sample HTML Page</title>\n" +
"</head>\n" +
"<body>\n" +
"\n" +
"<h1>This is a sample HTML page</h1>\n" +
"\n" +
"</body>\n" +
"</html>"

// ----------------------------------------------------------------------------------------------
// Test cases for orientation changes
// ----------------------------------------------------------------------------------------------
@Test
fun testMessageScreenIsRestoredOnOrientationChange() {
val instrumentation = InstrumentationRegistry.getInstrumentation()
val uiDevice = UiDevice.getInstance(instrumentation)

val heightPercentage = 95
val widthPercentage = 60
val settings = InAppMessageSettings.Builder()
.height(heightPercentage)
.width(widthPercentage)
.content(HTML_TEXT_SAMPLE)
.build()

val screenHeightDp = mutableStateOf(0.dp)
val screenWidthDp = mutableStateOf(0.dp)
val activityHeightDp = mutableStateOf(0.dp)
val activityWidthDp = mutableStateOf(0.dp)
composeTestRule.setContent { // setting our composable as content for test
// Get the screen dimensions
val currentConfiguration = LocalConfiguration.current
screenHeightDp.value = currentConfiguration.screenHeightDp.dp
screenWidthDp.value = currentConfiguration.screenWidthDp.dp

val activityRoot =
composeTestRule.activity.window.decorView.findViewById<View>(android.R.id.content)
activityHeightDp.value = with(LocalDensity.current) { activityRoot.height.toDp() }
activityWidthDp.value = with(LocalDensity.current) { activityRoot.width.toDp() }

MessageScreen(
presentationStateManager = presentationStateManager,
inAppMessageSettings = settings,
onCreated = { onCreatedCalled = true },
onDisposed = { onDisposedCalled = true },
onGestureDetected = { gesture -> detectedGestures.add(gesture) },
onBackPressed = { onBackPressed = true }
)
}

composeTestRule.waitForIdle()
composeTestRule.onNodeWithTag(MessageTestTags.MESSAGE_FRAME).assertDoesNotExist()

// Change the state of the presentation state manager to shown to display the message
presentationStateManager.onShown()
composeTestRule.waitForIdle()
MessageScreenTestHelper.validateMessageAppeared(
composeTestRule = composeTestRule,
withBackdrop = false,
clipped = false
)

// Verify that the message content is resized to fit the screen
val contentBounds = composeTestRule.onNodeWithTag(MessageTestTags.MESSAGE_CONTENT)
.getUnclippedBoundsInRoot()
val (expectedInitialHeight, expectedInitialWidth) = calculateDimensions(
screenHeightDp.value,
screenWidthDp.value,
activityHeightDp.value,
heightPercentage,
widthPercentage
)

MessageScreenTestHelper.validateViewSize(
contentBounds,
expectedInitialHeight,
expectedInitialWidth
)

assertTrue(onCreatedCalled)
assertFalse(onDisposedCalled)
assertFalse(onBackPressed)
assertTrue(detectedGestures.isEmpty())
resetState()

// Rotate the device to landscape
uiDevice.setOrientationLandscape()

// Wait for the device to stabilize
uiDevice.waitForIdle()
composeTestRule.waitForIdle()

// Verify that the message content is resized to fit the new orientation
MessageScreenTestHelper.validateMessageAppeared(
composeTestRule = composeTestRule,
withBackdrop = false,
clipped = false
)
val landscapeContentBounds = composeTestRule.onNodeWithTag(MessageTestTags.MESSAGE_CONTENT)
.getUnclippedBoundsInRoot()
val (expectedLandscapeHeight, expectedLandscapeWidth) = calculateDimensions(
screenHeightDp.value,
screenWidthDp.value,
activityHeightDp.value,
heightPercentage,
widthPercentage
)

MessageScreenTestHelper.validateViewSize(
landscapeContentBounds,
expectedLandscapeHeight,
expectedLandscapeWidth
)

// onCreated should not be called again due to orientation change restrictions
assertFalse(onCreatedCalled)
assertFalse(onDisposedCalled)
assertFalse(onBackPressed)
assertTrue(detectedGestures.isEmpty())
resetState()

// Rotate the device back to its original orientation
uiDevice.setOrientationNatural()

// Wait for the device to stabilize
uiDevice.waitForIdle()
composeTestRule.waitForIdle()
MessageScreenTestHelper.validateMessageAppeared(
composeTestRule = composeTestRule,
withBackdrop = false,
clipped = false
)

// Verify that the message content is restored to its original size
val (expectedNaturalHeight, expectedNaturalWidth) = calculateDimensions(
screenHeightDp.value,
screenWidthDp.value,
activityHeightDp.value,
heightPercentage,
widthPercentage
)

val naturalContentBounds = composeTestRule.onNodeWithTag(MessageTestTags.MESSAGE_CONTENT)
.getUnclippedBoundsInRoot()

MessageScreenTestHelper.validateViewSize(
naturalContentBounds,
expectedNaturalHeight,
expectedNaturalWidth
)
}

/**
* Calculates the expected height and width of the message content based on the screen dimensions
* If the height exceeds what is allowed by the activity (due to actionbar), it takes
* up the full height of the activity
* @param screenHeightDp the screen height in dp
* @param screenWidthDp the screen width in dp
* @param activityHeightDp the height of the activity in dp
* @param heightPercentage the percentage of the screen height the message content should take
* @param widthPercentage the percentage of the screen width the message content should take
* @return a pair of the expected height and width of the message content
*/
private fun calculateDimensions(
screenHeightDp: Dp,
screenWidthDp: Dp,
activityHeightDp: Dp,
heightPercentage: Int,
widthPercentage: Int
): Pair<Dp, Dp> {
val expectedHeight = if ((screenHeightDp * (heightPercentage / 100f)) > activityHeightDp) {
activityHeightDp
} else {
screenHeightDp * (heightPercentage / 100f)
}
val expectedWidth = screenWidthDp * (widthPercentage / 100f)

return Pair(expectedHeight, expectedWidth)
}

private fun resetState() {
onCreatedCalled = false
onDisposedCalled = false
onBackPressed = false
detectedGestures.clear()
}

@After
fun tearDown() {
resetState()
}
}
Loading
Loading