-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Set device_id and settings_json from MDM #6582
base: master
Are you sure you want to change the base?
Conversation
...app/src/main/java/org/odk/collect/android/application/initialization/ManagedConfigManager.kt
Outdated
Show resolved
Hide resolved
7dfce8c
to
334017f
Compare
@lognaturel I can't request your review as you are the creator of this pull request, but feel free to take a look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just a quick look, but I think there are a few pieces of criteria from the issue that might not work. Apologies if I'm missing something here. For example:
Given that Collect is not running and managed by MDM
When I change the settings_json key in my MDM system and those settings include a URL+username combination that does NOT match an existing project
Then a new project should be created with all of the settings I pushed
I don't think there's any code to cover this? As far as I can see we only deal with MDM configuration with a broadcast receiver, and that's only active while the FirstLaunchActivity
or MainMenuActiivty
are in a resumed state. The latter also means the following wouldn't work:
Given that Collect is running and managed by MDM
And I'm in the middle of form entry
When I change the device_id key in my MDM system
Then I should see that reflected next time I look at the settings or access deviceid from a form after returning to the main menu
As far as I can tell, we need to listen for broadcasts if the app is running (open or in the background) and the user is on the first launch screen, and we need to check for MDM config (with the RestrictionsManager
) when returning to the main menu (and while it's visible).
@seadowg Given that all the criteria mentioned in the issue should be met. |
@grzesiek2010 ah I'd missed the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've pointed out a few specific things and also wanted to make some broader comments
There's currently no tests that verify that this is all setup. I'd push for having instrumentation tests that check flows like starting the app for the first time on a device with MDM setup and there being a configuration change while the user is on the main menu etc. This initially seems a little awkward, but is pretty doable by managing the RestrictionsManager
in Dagger so that it can be swapped out with a stub in tests, and also introducing a BroadcastReceiverRegister
interface like this:
interface BroadcastReceiverRegister {
fun registerReceiver(context: Context, receiver: BroadcastReceiver)
}
That would allow us to have a test implementation that we can manually trigger (like we do with Scheduler
).
I also, think there's two refactors that could make these changes a little simpler, but they're just suggestions:
- Making first launch a Fragment and moving it into
MainMenuActivity
. This would make switching between two simpler (it could even use Jetpack Navigation) and allows sharing the dependency setup for projects, MDM etc - Flipping the relationship with
ProjectCreator
andProjectsDataService
so thatcreateNewProject
is a method on the data service.ProjectsDataService
could also have aconfigureProjectFromJSON
method that handles the "UPSERT" configuration and reduce the MDM specific code down to just "parsing" the bundle from broadcast/RestrictionsManager
.
collect_app/src/main/java/org/odk/collect/android/activities/FirstLaunchActivity.kt
Outdated
Show resolved
Hide resolved
...-device-management/src/main/java/org/odk/collect/mobiledevicemanagement/MDMConfigObserver.kt
Outdated
Show resolved
Hide resolved
26c1a5c
to
20bb367
Compare
Done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've still got to have a proper look at MDMConfigHandler
, but I'm finishing up for the day, and I thought it made sense to give you the thoughts I do have!
test-shared/src/main/java/org/odk/collect/testshared/FakeBroadcastReceiverRegister.kt
Show resolved
Hide resolved
import org.odk.collect.mobiledevicemanagement.MDMConfigHandler.Companion.SETTINGS_JSON_KEY | ||
|
||
@RunWith(AndroidJUnit4::class) | ||
class MobileDeviceManagementTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think every scenario here should save config and trigger a broadcast right? That's what will happen on device when the config changes (whether Collect is "listening" or not).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're outside the landing screen/main menu, there is no registered broadcast, so there's nothing to trigger. In those cases, it's enough to save the config, and it will be applied in onResume
the next time we open those screens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but the broadcast still happens. We want to trigger the FakeBroadcastReceiverRegister
to make sure that everything behaves as expected. The correct implementation will obviously not have a receiver registered at that point, so settings won't change etc. An incorrect implementation where the receiver was registered would cause a fail however.
.../src/androidTest/java/org/odk/collect/android/feature/projects/MobileDeviceManagementTest.kt
Outdated
Show resolved
Hide resolved
.../src/androidTest/java/org/odk/collect/android/feature/projects/MobileDeviceManagementTest.kt
Outdated
Show resolved
Hide resolved
.../src/androidTest/java/org/odk/collect/android/feature/projects/MobileDeviceManagementTest.kt
Show resolved
Hide resolved
@@ -1385,4 +1385,6 @@ | |||
<string name="view_or_change_polygon">View or change polygon</string> | |||
<!-- Text for the button that displays a map for viewing an already existing polygon --> | |||
<string name="view_polygon">View polygon</string> | |||
<!-- Text to describe a field for setting settings JSON in a mobile device management platform (MDM) --> | |||
<string name="settings_json">Settings JSON</string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be translated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that if the MDM provider supports multiple languages, it will used the localized string. I haven't verified this but the docs implied it.
collect_app/src/main/java/org/odk/collect/android/injection/config/AppDependencyComponent.java
Outdated
Show resolved
Hide resolved
...e-device-management/src/main/java/org/odk/collect/mobiledevicemanagement/MDMConfigHandler.kt
Outdated
Show resolved
Hide resolved
private val restrictionsReceiver = object : BroadcastReceiver() { | ||
override fun onReceive(context: Context, intent: Intent) { | ||
scheduler.immediate { | ||
mdmConfigHandler.applyConfig(restrictionsManager.applicationRestrictions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I'd said before, I think it would probably be nicer for us to be interacting with the ProjectsDataService
here, but I think there's a solid dividing line between the Android parts (broadcast receiver, lifecycle hooks and restrictions manager) and the domain logic (in MDMConfigHandler
) which should let us make a change to something like that later.
095f3a1
to
6751789
Compare
…ther projects present
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@grzesiek2010 sorry I hit the wrong button earlier and somehow ended up requesting a review from you rather than leaving one. |
@lognaturel @seadowg |
Yes, and it's a strange experience because it refreshes right before changing to another activity. I mentioned this when I demoed it for the Insiders call and Yaw asked about it. We agreed it's ok. That said, I found it surprising that it does refresh right before switching activities. Do you have an explanation for that? One other thing -- I couldn't get to get this branch as-is to work with TinyMDM. I ended up copying the restrictions block from the module manifest to the app manifest and that worked. |
For example, when you navigate from the main menu to the list of blank forms? If so, I don't see anything like that in tests.
This should be fixed by 1156ca0 |
Confirmed, thanks! On Galaxy A13 which is fairly slow, notice I tap "Start new form" and the project title changes: screencapture-1741821440389.mp4 |
Ah, it's just the project title. This happens because, in MainMenuFragment, we observe the current project and update the title whenever it changes. The update occurs when navigating to the list of forms, and if the main menu is still visible, it reflects the change. |
|
||
private fun applySettingsJson(managedConfig: Bundle) { | ||
if (managedConfig.containsKey(SETTINGS_JSON_KEY) && !managedConfig.getString(SETTINGS_JSON_KEY).isNullOrBlank()) { | ||
val settingsJson = managedConfig.getString(SETTINGS_JSON_KEY) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be defined later so you wouldn't need the !!
later.
} | ||
|
||
@Test | ||
fun `unsupported settings are ignored`() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little confused by this test: the ODKAppSettingsImporter
being used here is a mock, so I wouldn't expect any settings to get written anyway?
@lognaturel @grzesiek2010 I'm thinking we should file an issue around the project details not updating on the main menu. I think this is related to the way we interact with projects not being centralized (as I mention in #6582 (comment)) which is a hangover from before this PR. It'd be good to rework things so we more easily support project changes not being made directly by the user (which allows to just reload things explicitly). |
Exploration for #6581
This is intended to be a quick spike to explore how MDM works. To set
settings_json
, make sure to include both general and admin settings blocks.Out of scope:
Todo:
The easiest way I've found to try this is:
In Test DPC, search for "managed configuration", then select Collect and identify all keys from manifest.
Why is this the best possible solution? Were any other approaches considered?
The implementation's structure is the result of our discussions. We decided to listen for changes only in the main menu and the landing screen (when no projects are available). While this isn't perfect (settings may not be applied immediately), it’s a reasonable compromise that avoids introducing too many changes.
How does this change affect users? Describe intentional changes to behavior and behavior that could have accidentally been affected by code changes. In other words, what are the regression risks?
The cases described in the issues are a good reference for what should be tested. Other than that, I can't think of any specific part of the functionality that requires additional testing.
Do we need any specific form for testing your changes? If so, please attach one.
No.
Does this change require updates to documentation? If so, please file an issue here and include the link below.
Yes getodk/docs#1923
Before submitting this PR, please make sure you have:
./gradlew connectedAndroidTest
(or./gradlew testLab
) and confirmed all checks still passDateFormatsTest