Repository: AzureAD/microsoft-authentication-library-common-for-android
Pull request #2630: Move camera logic to CameraPermissionRequestHandler and add SdmQrPinManager , Fixes AB#3121976
Author: login: p3dr0rv
Labels: name: Skip-Consumers-Check
description: Only include this if making a breaking change purposefully, and there is an MSAL/ADAL/Broker PR
Created: 2025-04-25T03:52:37Z | Merged: 2025-04-30T05:47:32Z

- Move IBrokerRestrictionsManager.kt from broker to common
- Add SdmQrPinManager 
- Move camera consent code from WebViewAuthorizationFragment.java to CameraPermissionRequestHandler.kt
- Camera logic change: previously we show camera QR PIN consent dialog if request origin is from MS, otherwise we use default behavior. Now we use the SdmQrPinManager to determine if we should show the camera QR PIN consent dialog.  (see:  CameraPermissionRequestHandler.handle(request: PermissionRequest, context: Context)

Related PR: https://github.com/AzureAD/ad-accounts-for-android/pull/3089

Run manual UI test for validation https://identitydivision.visualstudio.com/Engineering/_testPlans/execute?planId=2007357&suiteId=2810290

[AB#3121976](https://identitydivision.visualstudio.com/fac9d424-53d2-45c0-91b5-ef6ba7a6bf26/_workitems/edit/3121976)
 


Diff:
diff --git a/changelog.txt b/changelog.txt
index 6e9a99be5d..81eafcf2d4 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,6 @@
 vNext
 ----------
+- [MINOR] Move camera logic to CameraPermissionRequestHandler and add SdmQrPinManager (#2630)
 - [MINOR] Pass Work Profile existence, OS Version, and Manufacturer to ESTS (#2627)
 - [MINOR] Add telemetry for the switch browser protocol (#2612)
 
diff --git a/common/src/main/java/com/microsoft/identity/common/internal/broker/IRestrictionsManager.kt b/common/src/main/java/com/microsoft/identity/common/internal/broker/IRestrictionsManager.kt
new file mode 100644
index 0000000000..ab870fbd39
--- /dev/null
+++ b/common/src/main/java/com/microsoft/identity/common/internal/broker/IRestrictionsManager.kt
@@ -0,0 +1,88 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import android.os.Bundle
+
+/**
+ * Helper class to read the app restrictions manager.
+ */
+interface IRestrictionsManager {
+    companion object BrokerRestrictionsManagerKeys {
+        /** Keys to group the values in the bundle. */
+        const val BOOLEAN_VALUES_KEY = "booleanValuesKey"
+        const val STRING_VALUES_KEY = "stringValuesKey"
+
+        /** Keys to be used in the app restrictions manager to read the values. */
+        // String keys
+        const val PREFERRED_AUTH_CONFIG = "preferred_auth_config"
+        // Boolean keys
+        const val SUPPRESS_CAMERA_CONSENT = "sdm_suppress_camera_consent"
+
+        /**
+         * Creates a request bundle with the keys to be requested from the app restrictions manager.
+         * The keys are filtered based on the type of the keys.
+         *
+         * @param stringKeys Keys to be requested from the app restrictions manager.
+         * @param booleanKeys Keys to be requested from the app restrictions manager.
+         * @return Bundle with the keys to be requested from the app restrictions manager.
+         */
+        @JvmStatic
+        @JvmOverloads
+        fun buildMultiValueRequest(stringKeys: Set<String>? = null, booleanKeys: Set<String>? = null): Bundle {
+            val stringList = stringKeys?.let { ArrayList(it) }
+            val booleanList = booleanKeys?.let { ArrayList(it) }
+            return Bundle().apply {
+                this.putStringArrayList(STRING_VALUES_KEY, stringList)
+                this.putStringArrayList(BOOLEAN_VALUES_KEY, booleanList)
+            }
+        }
+    }
+    /**
+     * Gets the [key] value from the [brokerAppPackageName] restrictions manager.
+     * Returns null if the key is not found or failed to read the value.
+     */
+    fun getString(key: String, brokerAppPackageName: String, defaultValue: String? = null): String?
+
+    /**
+     * Gets the [key] value from the [brokerAppPackageName] restrictions manager.
+     * Returns null if the key is not found or failed to read the value.
+     */
+    fun getBoolean(key: String, brokerAppPackageName: String, defaultValue: Boolean = false): Boolean
+
+    /**
+     * Reads the keys from the [bundleOfKeys] provided
+     * and returns a bundle with the values from the [brokerAppPackageName] restrictions manager.
+     * <p>
+     * The provided bundle should contain a key determining the type of the keys to be requested
+     * and the value should be an array list of keys.
+     * Example: if the bundle contains a key "stringValues" with an array list of keys ["key1s", "key2s"]
+     * and a key "booleanValues" with an array list of keys ["key0b"].
+     * Then the returned bundle will contain the values for the keys "key1s", "key2s" and "key0b".
+     *
+     *
+     * @param bundleOfKeys Bundle of keys to be requested from the app restrictions manager.
+     * @return Bundle with the values from the app restrictions manager.
+     */
+    fun getMultiValues(brokerAppPackageName: String, bundleOfKeys: Bundle) : Bundle
+}
diff --git a/common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt b/common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
new file mode 100644
index 0000000000..9f451ea9ff
--- /dev/null
+++ b/common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
@@ -0,0 +1,93 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ * by reading the restrictions manager of the Authenticator app.
+ *
+ * This object contains functions to check"
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `brokerAndroidBrokerPlatformComponentsFactory.create` is called.
+ *
+ * Note: If this object is not initialized, values default to `false` and `null`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    private val authenticatorPackageName = BrokerData.prodMicrosoftAuthenticator.packageName
+    private var restrictionsManager: IRestrictionsManager? = null
+
+    /**
+     * This method is used to initialize the SDM QR PIN manager with the broker restrictions manager.
+     * This is called when brokerAndroidBrokerPlatformComponentsFactory.create is called
+     * to ensure the manager is initialized with the correct broker restrictions manager.
+     */
+    fun initializeSdmQrPinManager(restrictionsManager: IRestrictionsManager) {
+        this.restrictionsManager = restrictionsManager
+    }
+
+    /**
+     * This method checks if the device preferred authentication config is set.
+     */
+    fun getPreferredAuthConfig(): String? {
+        val methodTag = "$TAG:getPreferredAuthConfig"
+        val defaultValue = null
+        restrictionsManager?.let { manager ->
+            return manager.getString(
+                key = PREFERRED_AUTH_CONFIG,
+                brokerAppPackageName = authenticatorPackageName,
+                defaultValue = defaultValue
+            )
+        } ?: run {
+            Logger.warn(methodTag, "Broker restrictions manager is not initialized.")
+            return defaultValue
+        }
+    }
+
+    /**
+     * This method checks if the camera consent is suppressed.
+     */
+    fun isCameraConsentSuppressed(): Boolean {
+        val methodTag = "$TAG:isCameraConsentSuppressed"
+        val defaultValue = false
+        restrictionsManager?.let { manager ->
+            return manager.getBoolean(
+                key = SUPPRESS_CAMERA_CONSENT,
+                brokerAppPackageName = authenticatorPackageName,
+                defaultValue = defaultValue
+            )
+        } ?: run {
+            Logger.warn(methodTag, "Broker restrictions manager is not initialized.")
+            return defaultValue
+        }
+    }
+}
diff --git a/common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/CameraPermissionRequestHandler.kt b/common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/CameraPermissionRequestHandler.kt
index 8377776f55..b085d022c3 100644
--- a/common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/CameraPermissionRequestHandler.kt
+++ b/common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/CameraPermissionRequestHandler.kt
@@ -22,7 +22,17 @@
 // THE SOFTWARE.
 package com.microsoft.identity.common.internal.providers.oauth2
 
+import android.Manifest
+import android.app.AlertDialog
+import android.content.Context
+import android.content.pm.PackageManager
 import android.webkit.PermissionRequest
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.core.content.ContextCompat
+import com.microsoft.identity.common.R
+import com.microsoft.identity.common.internal.broker.SdmQrPinManager
+import com.microsoft.identity.common.java.ui.PreferredAuthMethod
 import com.microsoft.identity.common.logging.Logger
 
 /**
@@ -30,25 +40,62 @@ import com.microsoft.identity.common.logging.Logger
  * Note: This class is compatible only with API level 21 and above;
  * functionality will not behave as expected on lower versions.
  */
-class CameraPermissionRequestHandler {
+class CameraPermissionRequestHandler(fragment: WebViewAuthorizationFragment) {
+
+    private companion object {
+        private const val TAG = "CameraPermissionRequestHandler"
+        private const val MICROSOFT_CLOUD_URL: String = "https://login.microsoftonline.com/"
+        private val cameraResource = arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE)
+    }
+
+    private val activityResultLauncher: ActivityResultLauncher<String> =
+        fragment.registerForActivityResult(ActivityResultContracts.RequestPermission()) {
+            permissionGranted: Boolean ->
+            Logger.info(TAG, "Camera permission granted: $permissionGranted")
+            if (permissionGranted) {
+                grant()
+            } else {
+                deny()
+            }
+        }
 
     private var currentPermissionRequest : PermissionRequest? = null
 
     /**
-     * Check if the permission was granted.
-     *
-     * @return true if the permission is granted.
+     * Keeps track of the camera permission request state.
      */
     private var isGranted = false
 
+    /**
+     * Handles the camera permission request.
+     * <p>
+     * If the request is valid, it will be handled by the qrPinHandler or defaultHandler.
+     * If the request is not valid, it will be denied.
+     *
+     * @param request The permission request to handle.
+     */
+    fun handle(request: PermissionRequest, context: Context) {
+        val  methodTag = "$TAG:handle"
+        // Check if the request is valid.
+        if (isValid(request)) {
+            currentPermissionRequest = request
+            isGranted = false
+        } else {
+            Logger.warn(methodTag, "Permission request is not valid, returning.")
+            return
+        }
+        if(isQrPinRequest()) {
+            qrPinHandler(context)
+        } else {
+            defaultHandler(context)
+        }
+    }
+
     /**
      * Call this method to grant the permission to access the camera resource.
      * The granted permission is only valid for the current WebView.
-     *
-     *
-     * Note: This method is only available on API level 21 or higher.
      */
-    fun grant() {
+    private fun grant() {
         currentPermissionRequest?.let {
             it.grant(cameraResource)
             isGranted = true
@@ -57,11 +104,8 @@ class CameraPermissionRequestHandler {
 
     /**
      * Call this method to deny the permission to access the camera resource.
-     *
-     *
-     * Note: This method is only available on API level 21 or higher.
      */
-    fun deny() {
+    private fun deny() {
         currentPermissionRequest?.let {
             it.deny()
             isGranted = false
@@ -70,16 +114,17 @@ class CameraPermissionRequestHandler {
 
     /**
      * Check if the given [PermissionRequest] is valid.
-     * If valid, set the current permission request and return true.
+     * If valid return true.
      * If not valid, deny the request and return false.
      * <p>
      * A request is considered valid if:
      * - The request is for the camera resource only.
      * - The request is not a repeated request (i.e., not for the same origin and resources).
-     *
+     * We can only grant or deny permissions for video capture/camera.
+     * To avoid unintentionally granting requests for not defined permissions
      */
-    fun setIfValid(request: PermissionRequest): Boolean {
-        val methodTag = "$TAG:setIfValid"
+    private fun isValid(request: PermissionRequest): Boolean {
+        val methodTag = "$TAG:isValid"
         if (!isForCamera(request)) {
             Logger.warn(methodTag, "Permission request is not for camera.")
             request.deny()
@@ -97,19 +142,92 @@ class CameraPermissionRequestHandler {
             return false
         } else {
             Logger.info(methodTag, "Valid new request.")
-            setCurrentPermissionRequest(request)
             return true
         }
     }
 
     /**
-     * Set the current permission request.
+     * Check if the current permission request is a QR code pin request.
+     * <p>
+     * A request is considered a QR code pin request if:
+     * - The origin of the request is the Microsoft cloud URL.
+     * - The device is on SDM QR pin mode.
+     *
+     * @return true if the current permission request is a QR code pin request, false otherwise.
+     */
+    private fun isQrPinRequest() : Boolean {
+        return currentPermissionRequest?.origin != null
+                && MICROSOFT_CLOUD_URL.equals(currentPermissionRequest?.origin.toString(), ignoreCase = true)
+                && PreferredAuthMethod.QR.value.equals(SdmQrPinManager.getPreferredAuthConfig())
+    }
+
+    /**
+     * Handles the camera permission request for the app.
+     * If the camera permission is already granted, it will grant the permission.
+     * Otherwise, it will request the camera permission.
+     */
+    private fun defaultHandler(context: Context) {
+        val methodTag = "$TAG:defaultHandler"
+        if (appHasCameraPermission(context)) {
+            Logger.info(methodTag, "App level camera permission already granted, silent grant.")
+            grant()
+        } else {
+            requestCameraPermission()
+        }
+    }
+
+    /**
+     * Handles the camera permission request for QR code scanning.
+     * If the camera permission is already granted and the camera consent suppress is enabled,
+     * it will grant the permission. otherwise, it will explaining why the camera permission is required.
+     * If the camera permission is not granted, it will request the camera permission.
+     */
+    private fun qrPinHandler(context: Context) {
+        val  methodTag = "$TAG:handleQrPin"
+        if (appHasCameraPermission(context)) {
+            Logger.info(methodTag, "App level camera permission already granted.")
+            if (SdmQrPinManager.isCameraConsentSuppressed()) {
+                Logger.info(methodTag, "Camera consent suppress is enabled.")
+                grant()
+            } else {
+                Logger.info(methodTag, "Camera consent suppress is not enabled.")
+                showQrPinCameraRationale(context)
+            }
+        } else {
+            requestCameraPermission()
+        }
+    }
+
+    /**
+     * Determines whatever if the camera permission has been granted.
      *
-     * @param permissionRequest The permission request to set.
+     * @return true if the camera permission has been granted, false otherwise.
+     */
+    private fun appHasCameraPermission(context: Context): Boolean {
+        return (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
+                == PackageManager.PERMISSION_GRANTED)
+    }
+
+    /**
+     * Shows a dialog to the user explaining why the camera permission is required.
+     * If the user accepts the dialog, the camera permission request will be launched.
+     * If the user denies the dialog, the camera permission request will be denied.
      */
-    private fun setCurrentPermissionRequest(permissionRequest: PermissionRequest) {
-        currentPermissionRequest = permissionRequest
-        isGranted = false
+    private fun showQrPinCameraRationale(context: Context) {
+        val methodTag = "$TAG:showQrPinCameraRationale"
+        val builder = AlertDialog.Builder(context)
+        builder.setMessage(R.string.qr_code_rationale_message)
+            .setTitle(R.string.qr_code_rationale_header)
+            .setCancelable(false)
+            .setPositiveButton(R.string.qr_code_rationale_allow) { _, _ ->
+                Logger.info(methodTag, "User accepted camera permission rationale.")
+                requestCameraPermission()
+            }
+            .setNegativeButton(R.string.qr_code_rationale_block) { _, _ ->
+                Logger.info(methodTag, "User denied camera permission rationale.")
+                deny()
+            }
+        builder.show()
     }
 
     /**
@@ -154,10 +272,14 @@ class CameraPermissionRequestHandler {
                 PermissionRequest.RESOURCE_VIDEO_CAPTURE == request.resources[0]
     }
 
-    companion object {
-        private const val TAG = "CameraPermissionRequestHandler"
-        private val cameraResource = arrayOf(
-            PermissionRequest.RESOURCE_VIDEO_CAPTURE
-        )
+    /**
+     * Launches the camera permission request for the app.
+     * Note: if the permission was already granted or denied,
+     * the user will not be prompted and it will go directly to the callback.
+     * Using the current state of the permission.
+     *
+     */
+    private fun requestCameraPermission() {
+        activityResultLauncher.launch(Manifest.permission.CAMERA)
     }
 }
diff --git a/common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/WebViewAuthorizationFragment.java b/common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/WebViewAuthorizationFragment.java
index 6589917b89..a9ff41de15 100644
--- a/common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/WebViewAuthorizationFragment.java
+++ b/common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/WebViewAuthorizationFragment.java
@@ -22,12 +22,9 @@
 // THE SOFTWARE.
 package com.microsoft.identity.common.internal.providers.oauth2;
 
-import android.Manifest;
 import android.annotation.SuppressLint;
 import android.app.Activity;
-import android.app.AlertDialog;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.os.Build;
 import android.os.Bundle;
@@ -42,11 +39,9 @@
 import android.widget.ProgressBar;
 
 import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
-import androidx.core.content.ContextCompat;
 import androidx.fragment.app.FragmentActivity;
 
 import com.microsoft.identity.common.R;
@@ -96,7 +91,6 @@ public class WebViewAuthorizationFragment extends AuthorizationFragment {
 
     @VisibleForTesting
     private static final String PKEYAUTH_STATUS = "pkeyAuthStatus";
-    private static final String MICROSOFT_CLOUD_URL = "https://login.microsoftonline.com/";
 
     private WebView mWebView;
 
@@ -121,7 +115,7 @@ public class WebViewAuthorizationFragment extends AuthorizationFragment {
 
     private boolean webViewZoomEnabled;
 
-    private final CameraPermissionRequestHandler mCameraPermissionRequestHandler = new CameraPermissionRequestHandler();
+    private final CameraPermissionRequestHandler mCameraPermissionRequestHandler = new CameraPermissionRequestHandler(this);
 
     // This is used by LegacyFido2ApiManager to launch a PendingIntent received by the legacy API.
     private ActivityResultLauncher<LegacyFido2ApiObject> mFidoLauncher;
@@ -240,7 +234,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
                 new OnPageLoadedCallback() {
                     @Override
                     public void onPageLoaded(final String url) {
-                        // Reset the camera permission request when a new page is loaded.
                         final String[] javascriptToExecute = new String[1];
                         mProgressBar.setVisibility(View.INVISIBLE);
                         try {
@@ -326,29 +319,7 @@ public void onPermissionRequest(final PermissionRequest request) {
                             "Permission requested from:" +request.getOrigin() +
                                     " for resources:" + Arrays.toString(request.getResources())
                     );
-                    // We can only grant or deny permissions for video capture/camera.
-                    // To avoid unintentionally granting requests for not defined permissions
-                    // we check if the request is for camera.
-                    if (!mCameraPermissionRequestHandler.setIfValid(request)) {
-                        Logger.warn(methodTag, "Permission request is not valid, returning.");
-                        return;
-                    }
-
-                    // If the OS level permission was granted previously,
-                    // we show the rationale to confirm the consent with the current user.
-                    // Otherwise, show the system prompt.
-                    if (isAppCameraPermissionGranted()) {
-                        Logger.info(methodTag, "App level camera permission already granted.");
-                        if(request.getOrigin() != null &&  MICROSOFT_CLOUD_URL.equalsIgnoreCase(request.getOrigin().toString())) {
-                            Logger.info(methodTag, "Require rationale.");
-                            showCameraRationale();
-                        } else {
-                            Logger.info(methodTag, "Rationale not needed.");
-                            mCameraPermissionRequestHandler.grant();
-                        }
-                    } else {
-                        requestCameraPermission();
-                    }
+                    mCameraPermissionRequestHandler.handle(request, requireContext());
                 });
             }
 
@@ -364,62 +335,6 @@ public Bitmap getDefaultVideoPoster() {
         });
     }
 
-    /**
-     * Determines whatever if the camera permission has been granted.
-     *
-     * @return true if the camera permission has been granted, false otherwise.
-     */
-    private boolean isAppCameraPermissionGranted() {
-        return ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
-                == PackageManager.PERMISSION_GRANTED;
-    }
-
-    private final ActivityResultLauncher<String> cameraRequestActivity = registerForActivityResult(
-            new ActivityResultContracts.RequestPermission(),
-            permissionGranted   -> {
-                Logger.info(TAG, "Camera permission granted: " + permissionGranted);
-                if (permissionGranted) {
-                    mCameraPermissionRequestHandler.grant();
-                }
-                else {
-                    mCameraPermissionRequestHandler.deny();
-                }
-            }
-    );
-
-    /**
-     * Launches the camera permission request for the app.
-     * Note: if the permission was already granted or denied,
-     * the user will not be prompted and it will go directly to the callback.
-     * Using the current state of the permission.
-     *
-     */
-    private void requestCameraPermission() {
-        cameraRequestActivity.launch(Manifest.permission.CAMERA);
-    }
-
-    /**
-     * Shows a dialog to the user explaining why the camera permission is required.
-     * If the user accepts the dialog, the camera permission request will be launched.
-     * If the user denies the dialog, the camera permission request will be denied.
-     */
-    private void showCameraRationale() {
-        final String methodTag = TAG + ":showCameraRationale";
-        final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
-        builder.setMessage(R.string.qr_code_rationale_message)
-                .setTitle(R.string.qr_code_rationale_header)
-                .setCancelable(false)
-                .setPositiveButton(R.string.qr_code_rationale_allow, (dialog, id) -> {
-                    Logger.info(methodTag, "User accepted camera permission rationale.");
-                    requestCameraPermission();
-                })
-                .setNegativeButton(R.string.qr_code_rationale_block, (dialog, id) -> {
-                    Logger.info(methodTag, "User denied camera permission rationale.");
-                    mCameraPermissionRequestHandler.deny();
-                });
-        builder.show();
-    }
-
     /**
      * Loads starting authorization request url into WebView.
      */


Reviews:
user: login: mohitc1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T23:42:23Z
user: login: mohitc1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T23:43:16Z
user: login: p3dr0rv
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T00:24:47Z
user: login: mohitc1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T04:53:51Z
user: login: mohitc1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T05:02:42Z
user: login: p3dr0rv
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T18:07:08Z
user: login: p3dr0rv
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T18:14:37Z
user: login: p3dr0rv
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T19:50:10Z
user: login: mohitc1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:55:02Z
user: login: mohitc1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:55:10Z
user: login: mohitc1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T21:02:27Z
user: login: mohitc1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T21:03:03Z
user: login: mohitc1
body: Left some suggestions
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T21:39:20Z
user: login: p3dr0rv
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T22:32:23Z
user: login: p3dr0rv
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T22:33:26Z
user: login: somalaya
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T00:00:39Z
user: login: somalaya
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T00:09:54Z
user: login: p3dr0rv
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T00:11:32Z
user: login: p3dr0rv
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T00:12:26Z
user: login: somalaya
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T00:37:29Z

Review comments:
diff_hunk: @@ -0,0 +1,104 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.buildMultiValueRequest
+import com.microsoft.identity.common.java.ui.PreferredAuthMethod
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains flags that indicate:
+ * - Whether the device is currently in SDM QR PIN mode.
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+ * since apps always contact the broker to get the preferred authentication method
+ * before starting the QR + PIN authentication flow.
+ *
+ * Note: If this object is not initialized, both flags default to `false`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    /**
+     * This is the preferred authentication method for the device on SDM mode.
+     * This is set in the Authenticator app, using app configuration policies for managed Android Enterprise devices.
+     */
+    var preferredAuthMethod: String? = null
+
+    /**
+     * This is a flag to indicate if the device is on SDM QR PIN mode.
+     * If this is true, the device should prompt the user for camera consent.
+     */
+    var isDeviceOnSdmQrPinAuth = false
+        private set
+
+    /**
+     * This is a flag to indicate if the camera consent should be suppressed.
+     * If this is true, the device should not prompt the user for camera consent.
+     */
+    var isCameraConsentSuppressed = false
+        private set
+
+    /**
+     * This variable is used to store the last update time of the SDM QR PIN manager.
+     */
+    private var lastUpdateTime: Long = 0L
+
+    /**
+     * This method initializes the SDM QR PIN manager by checking the broker restrictions manager.
+     * It sets the [isDeviceOnSdmQrPinAuth], [preferredAuthMethod] and [isCameraConsentSuppressed] flags.
+     * This method is called each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+     * because the restrictions rarely change, only when a new policy is pushed to the device.
+     *
+     * @param brokerRestrictionsManager The broker restrictions manager to check the restrictions.
+     */
+    fun initializeSdmQrPinManager(brokerRestrictionsManager: IBrokerRestrictionsManager) {
+        Logger.info(TAG, "Initializing SDM QR PIN manager.")
+        val multiValueRequest = buildMultiValueRequest(
+            booleanKeys = setOf(SUPPRESS_CAMERA_CONSENT),
+            stringKeys = setOf(PREFERRED_AUTH_CONFIG)
+        )
+        val multiValues = brokerRestrictionsManager.getMultiValues(
+            brokerAppPackageName = BrokerData.prodMicrosoftAuthenticator.packageName,
+            bundleOfKeys = multiValueRequest
+        )
+        preferredAuthMethod = multiValues.getString(PREFERRED_AUTH_CONFIG)
+        if (preferredAuthMethod == PreferredAuthMethod.QR.value) {
+            isDeviceOnSdmQrPinAuth = true
+        }
+        isCameraConsentSuppressed = multiValues.getBoolean(SUPPRESS_CAMERA_CONSENT)
+        Logger.info(
+            TAG,
+            "preferredAuthMethod: $preferredAuthMethod," +
+                    " isCameraConsentSuppressed: $isCameraConsentSuppressed"
+        )
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: mohitc1
body: Any reason you're doing reads in initialize itself?

Can we do it when getPreferredAuthMethod() and isDeviceOnSdmQrPinAuth is called?
created_at: 2025-04-28T23:42:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,88 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import android.os.Bundle
+
+/**
+ * Helper class to read the app restrictions manager of the current broker app or another broker app.
+ */
+interface IBrokerRestrictionsManager {
path: common/src/main/java/com/microsoft/identity/common/internal/broker/IBrokerRestrictionsManager.kt
user: login: mohitc1
body: >IBrokerRestrictionsManager [](http://example.com/codeflow?start=10&length=26)

Rename to IRestrictionsManager?
created_at: 2025-04-28T23:43:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,104 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.buildMultiValueRequest
+import com.microsoft.identity.common.java.ui.PreferredAuthMethod
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains flags that indicate:
+ * - Whether the device is currently in SDM QR PIN mode.
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+ * since apps always contact the broker to get the preferred authentication method
+ * before starting the QR + PIN authentication flow.
+ *
+ * Note: If this object is not initialized, both flags default to `false`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    /**
+     * This is the preferred authentication method for the device on SDM mode.
+     * This is set in the Authenticator app, using app configuration policies for managed Android Enterprise devices.
+     */
+    var preferredAuthMethod: String? = null
+
+    /**
+     * This is a flag to indicate if the device is on SDM QR PIN mode.
+     * If this is true, the device should prompt the user for camera consent.
+     */
+    var isDeviceOnSdmQrPinAuth = false
+        private set
+
+    /**
+     * This is a flag to indicate if the camera consent should be suppressed.
+     * If this is true, the device should not prompt the user for camera consent.
+     */
+    var isCameraConsentSuppressed = false
+        private set
+
+    /**
+     * This variable is used to store the last update time of the SDM QR PIN manager.
+     */
+    private var lastUpdateTime: Long = 0L
+
+    /**
+     * This method initializes the SDM QR PIN manager by checking the broker restrictions manager.
+     * It sets the [isDeviceOnSdmQrPinAuth], [preferredAuthMethod] and [isCameraConsentSuppressed] flags.
+     * This method is called each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+     * because the restrictions rarely change, only when a new policy is pushed to the device.
+     *
+     * @param brokerRestrictionsManager The broker restrictions manager to check the restrictions.
+     */
+    fun initializeSdmQrPinManager(brokerRestrictionsManager: IBrokerRestrictionsManager) {
+        Logger.info(TAG, "Initializing SDM QR PIN manager.")
+        val multiValueRequest = buildMultiValueRequest(
+            booleanKeys = setOf(SUPPRESS_CAMERA_CONSENT),
+            stringKeys = setOf(PREFERRED_AUTH_CONFIG)
+        )
+        val multiValues = brokerRestrictionsManager.getMultiValues(
+            brokerAppPackageName = BrokerData.prodMicrosoftAuthenticator.packageName,
+            bundleOfKeys = multiValueRequest
+        )
+        preferredAuthMethod = multiValues.getString(PREFERRED_AUTH_CONFIG)
+        if (preferredAuthMethod == PreferredAuthMethod.QR.value) {
+            isDeviceOnSdmQrPinAuth = true
+        }
+        isCameraConsentSuppressed = multiValues.getBoolean(SUPPRESS_CAMERA_CONSENT)
+        Logger.info(
+            TAG,
+            "preferredAuthMethod: $preferredAuthMethod," +
+                    " isCameraConsentSuppressed: $isCameraConsentSuppressed"
+        )
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: p3dr0rv
body: Those values ​​are unlikely to change since they are set by Intune policy, so I was thinking of avoiding calls to the broker and restrictions manager by simply reading all the values ​​at once and holding them for a while until the broker process is killed.
created_at: 2025-04-29T00:24:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,104 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.buildMultiValueRequest
+import com.microsoft.identity.common.java.ui.PreferredAuthMethod
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains flags that indicate:
+ * - Whether the device is currently in SDM QR PIN mode.
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+ * since apps always contact the broker to get the preferred authentication method
+ * before starting the QR + PIN authentication flow.
+ *
+ * Note: If this object is not initialized, both flags default to `false`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    /**
+     * This is the preferred authentication method for the device on SDM mode.
+     * This is set in the Authenticator app, using app configuration policies for managed Android Enterprise devices.
+     */
+    var preferredAuthMethod: String? = null
+
+    /**
+     * This is a flag to indicate if the device is on SDM QR PIN mode.
+     * If this is true, the device should prompt the user for camera consent.
+     */
+    var isDeviceOnSdmQrPinAuth = false
+        private set
+
+    /**
+     * This is a flag to indicate if the camera consent should be suppressed.
+     * If this is true, the device should not prompt the user for camera consent.
+     */
+    var isCameraConsentSuppressed = false
+        private set
+
+    /**
+     * This variable is used to store the last update time of the SDM QR PIN manager.
+     */
+    private var lastUpdateTime: Long = 0L
+
+    /**
+     * This method initializes the SDM QR PIN manager by checking the broker restrictions manager.
+     * It sets the [isDeviceOnSdmQrPinAuth], [preferredAuthMethod] and [isCameraConsentSuppressed] flags.
+     * This method is called each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+     * because the restrictions rarely change, only when a new policy is pushed to the device.
+     *
+     * @param brokerRestrictionsManager The broker restrictions manager to check the restrictions.
+     */
+    fun initializeSdmQrPinManager(brokerRestrictionsManager: IBrokerRestrictionsManager) {
+        Logger.info(TAG, "Initializing SDM QR PIN manager.")
+        val multiValueRequest = buildMultiValueRequest(
+            booleanKeys = setOf(SUPPRESS_CAMERA_CONSENT),
+            stringKeys = setOf(PREFERRED_AUTH_CONFIG)
+        )
+        val multiValues = brokerRestrictionsManager.getMultiValues(
+            brokerAppPackageName = BrokerData.prodMicrosoftAuthenticator.packageName,
+            bundleOfKeys = multiValueRequest
+        )
+        preferredAuthMethod = multiValues.getString(PREFERRED_AUTH_CONFIG)
+        if (preferredAuthMethod == PreferredAuthMethod.QR.value) {
+            isDeviceOnSdmQrPinAuth = true
+        }
+        isCameraConsentSuppressed = multiValues.getBoolean(SUPPRESS_CAMERA_CONSENT)
+        Logger.info(
+            TAG,
+            "preferredAuthMethod: $preferredAuthMethod," +
+                    " isCameraConsentSuppressed: $isCameraConsentSuppressed"
+        )
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: mohitc1
body: Is GetPreferredAuthMethodMsalBrokerOperation called only once by caller?

This method is called by GetPreferredAuthMethodMsalBrokerOperation every time 
created_at: 2025-04-29T04:53:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,104 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.buildMultiValueRequest
+import com.microsoft.identity.common.java.ui.PreferredAuthMethod
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains flags that indicate:
+ * - Whether the device is currently in SDM QR PIN mode.
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+ * since apps always contact the broker to get the preferred authentication method
+ * before starting the QR + PIN authentication flow.
+ *
+ * Note: If this object is not initialized, both flags default to `false`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    /**
+     * This is the preferred authentication method for the device on SDM mode.
+     * This is set in the Authenticator app, using app configuration policies for managed Android Enterprise devices.
+     */
+    var preferredAuthMethod: String? = null
+
+    /**
+     * This is a flag to indicate if the device is on SDM QR PIN mode.
+     * If this is true, the device should prompt the user for camera consent.
+     */
+    var isDeviceOnSdmQrPinAuth = false
+        private set
+
+    /**
+     * This is a flag to indicate if the camera consent should be suppressed.
+     * If this is true, the device should not prompt the user for camera consent.
+     */
+    var isCameraConsentSuppressed = false
+        private set
+
+    /**
+     * This variable is used to store the last update time of the SDM QR PIN manager.
+     */
+    private var lastUpdateTime: Long = 0L
+
+    /**
+     * This method initializes the SDM QR PIN manager by checking the broker restrictions manager.
+     * It sets the [isDeviceOnSdmQrPinAuth], [preferredAuthMethod] and [isCameraConsentSuppressed] flags.
+     * This method is called each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+     * because the restrictions rarely change, only when a new policy is pushed to the device.
+     *
+     * @param brokerRestrictionsManager The broker restrictions manager to check the restrictions.
+     */
+    fun initializeSdmQrPinManager(brokerRestrictionsManager: IBrokerRestrictionsManager) {
+        Logger.info(TAG, "Initializing SDM QR PIN manager.")
+        val multiValueRequest = buildMultiValueRequest(
+            booleanKeys = setOf(SUPPRESS_CAMERA_CONSENT),
+            stringKeys = setOf(PREFERRED_AUTH_CONFIG)
+        )
+        val multiValues = brokerRestrictionsManager.getMultiValues(
+            brokerAppPackageName = BrokerData.prodMicrosoftAuthenticator.packageName,
+            bundleOfKeys = multiValueRequest
+        )
+        preferredAuthMethod = multiValues.getString(PREFERRED_AUTH_CONFIG)
+        if (preferredAuthMethod == PreferredAuthMethod.QR.value) {
+            isDeviceOnSdmQrPinAuth = true
+        }
+        isCameraConsentSuppressed = multiValues.getBoolean(SUPPRESS_CAMERA_CONSENT)
+        Logger.info(
+            TAG,
+            "preferredAuthMethod: $preferredAuthMethod," +
+                    " isCameraConsentSuppressed: $isCameraConsentSuppressed"
+        )
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: mohitc1
body: Is this always supposed to be called before CameraPermissionRequestHandler runs?
created_at: 2025-04-29T05:02:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,104 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.buildMultiValueRequest
+import com.microsoft.identity.common.java.ui.PreferredAuthMethod
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains flags that indicate:
+ * - Whether the device is currently in SDM QR PIN mode.
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+ * since apps always contact the broker to get the preferred authentication method
+ * before starting the QR + PIN authentication flow.
+ *
+ * Note: If this object is not initialized, both flags default to `false`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    /**
+     * This is the preferred authentication method for the device on SDM mode.
+     * This is set in the Authenticator app, using app configuration policies for managed Android Enterprise devices.
+     */
+    var preferredAuthMethod: String? = null
+
+    /**
+     * This is a flag to indicate if the device is on SDM QR PIN mode.
+     * If this is true, the device should prompt the user for camera consent.
+     */
+    var isDeviceOnSdmQrPinAuth = false
+        private set
+
+    /**
+     * This is a flag to indicate if the camera consent should be suppressed.
+     * If this is true, the device should not prompt the user for camera consent.
+     */
+    var isCameraConsentSuppressed = false
+        private set
+
+    /**
+     * This variable is used to store the last update time of the SDM QR PIN manager.
+     */
+    private var lastUpdateTime: Long = 0L
+
+    /**
+     * This method initializes the SDM QR PIN manager by checking the broker restrictions manager.
+     * It sets the [isDeviceOnSdmQrPinAuth], [preferredAuthMethod] and [isCameraConsentSuppressed] flags.
+     * This method is called each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+     * because the restrictions rarely change, only when a new policy is pushed to the device.
+     *
+     * @param brokerRestrictionsManager The broker restrictions manager to check the restrictions.
+     */
+    fun initializeSdmQrPinManager(brokerRestrictionsManager: IBrokerRestrictionsManager) {
+        Logger.info(TAG, "Initializing SDM QR PIN manager.")
+        val multiValueRequest = buildMultiValueRequest(
+            booleanKeys = setOf(SUPPRESS_CAMERA_CONSENT),
+            stringKeys = setOf(PREFERRED_AUTH_CONFIG)
+        )
+        val multiValues = brokerRestrictionsManager.getMultiValues(
+            brokerAppPackageName = BrokerData.prodMicrosoftAuthenticator.packageName,
+            bundleOfKeys = multiValueRequest
+        )
+        preferredAuthMethod = multiValues.getString(PREFERRED_AUTH_CONFIG)
+        if (preferredAuthMethod == PreferredAuthMethod.QR.value) {
+            isDeviceOnSdmQrPinAuth = true
+        }
+        isCameraConsentSuppressed = multiValues.getBoolean(SUPPRESS_CAMERA_CONSENT)
+        Logger.info(
+            TAG,
+            "preferredAuthMethod: $preferredAuthMethod," +
+                    " isCameraConsentSuppressed: $isCameraConsentSuppressed"
+        )
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: p3dr0rv
body: Before making a token request,
1 Teams calls the GetPreferredAuthMethodMsalBrokerOperation method. 
2 If the preferred authentication method is QR+PIN, Teams displays a button for signing in using the camera. 
3 The user then logs in with QR+PIN.

Teams and other applications using this authentication method always call GetPreferredAuthMethodMsalBrokerOperation before making a token request with the camera. This is because they will only use QR+PIN authentication if the preferred method is QR+PIN, and to determine the method, they need to call GetPreferredAuthMethodMsalBrokerOperation.
created_at: 2025-04-29T18:07:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,104 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.buildMultiValueRequest
+import com.microsoft.identity.common.java.ui.PreferredAuthMethod
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains flags that indicate:
+ * - Whether the device is currently in SDM QR PIN mode.
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+ * since apps always contact the broker to get the preferred authentication method
+ * before starting the QR + PIN authentication flow.
+ *
+ * Note: If this object is not initialized, both flags default to `false`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    /**
+     * This is the preferred authentication method for the device on SDM mode.
+     * This is set in the Authenticator app, using app configuration policies for managed Android Enterprise devices.
+     */
+    var preferredAuthMethod: String? = null
+
+    /**
+     * This is a flag to indicate if the device is on SDM QR PIN mode.
+     * If this is true, the device should prompt the user for camera consent.
+     */
+    var isDeviceOnSdmQrPinAuth = false
+        private set
+
+    /**
+     * This is a flag to indicate if the camera consent should be suppressed.
+     * If this is true, the device should not prompt the user for camera consent.
+     */
+    var isCameraConsentSuppressed = false
+        private set
+
+    /**
+     * This variable is used to store the last update time of the SDM QR PIN manager.
+     */
+    private var lastUpdateTime: Long = 0L
+
+    /**
+     * This method initializes the SDM QR PIN manager by checking the broker restrictions manager.
+     * It sets the [isDeviceOnSdmQrPinAuth], [preferredAuthMethod] and [isCameraConsentSuppressed] flags.
+     * This method is called each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+     * because the restrictions rarely change, only when a new policy is pushed to the device.
+     *
+     * @param brokerRestrictionsManager The broker restrictions manager to check the restrictions.
+     */
+    fun initializeSdmQrPinManager(brokerRestrictionsManager: IBrokerRestrictionsManager) {
+        Logger.info(TAG, "Initializing SDM QR PIN manager.")
+        val multiValueRequest = buildMultiValueRequest(
+            booleanKeys = setOf(SUPPRESS_CAMERA_CONSENT),
+            stringKeys = setOf(PREFERRED_AUTH_CONFIG)
+        )
+        val multiValues = brokerRestrictionsManager.getMultiValues(
+            brokerAppPackageName = BrokerData.prodMicrosoftAuthenticator.packageName,
+            bundleOfKeys = multiValueRequest
+        )
+        preferredAuthMethod = multiValues.getString(PREFERRED_AUTH_CONFIG)
+        if (preferredAuthMethod == PreferredAuthMethod.QR.value) {
+            isDeviceOnSdmQrPinAuth = true
+        }
+        isCameraConsentSuppressed = multiValues.getBoolean(SUPPRESS_CAMERA_CONSENT)
+        Logger.info(
+            TAG,
+            "preferredAuthMethod: $preferredAuthMethod," +
+                    " isCameraConsentSuppressed: $isCameraConsentSuppressed"
+        )
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: p3dr0rv
body: I chose to implement it this way to avoid making unnecessary calls for users who will use the camera but not QR+PIN. However, I have no issue moving it to where getPreferredAuthMethod() and isDeviceOnSdmQrPinAuth are called. As mentioned, this was just an optimization, but I will move it to be on the safe side in case the pattern changes. In this case, I will pass the broker restriction manager when we initialize platform components.
created_at: 2025-04-29T18:14:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,104 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.internal.broker.IBrokerRestrictionsManager.BrokerRestrictionsManagerKeys.buildMultiValueRequest
+import com.microsoft.identity.common.java.ui.PreferredAuthMethod
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains flags that indicate:
+ * - Whether the device is currently in SDM QR PIN mode.
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+ * since apps always contact the broker to get the preferred authentication method
+ * before starting the QR + PIN authentication flow.
+ *
+ * Note: If this object is not initialized, both flags default to `false`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    /**
+     * This is the preferred authentication method for the device on SDM mode.
+     * This is set in the Authenticator app, using app configuration policies for managed Android Enterprise devices.
+     */
+    var preferredAuthMethod: String? = null
+
+    /**
+     * This is a flag to indicate if the device is on SDM QR PIN mode.
+     * If this is true, the device should prompt the user for camera consent.
+     */
+    var isDeviceOnSdmQrPinAuth = false
+        private set
+
+    /**
+     * This is a flag to indicate if the camera consent should be suppressed.
+     * If this is true, the device should not prompt the user for camera consent.
+     */
+    var isCameraConsentSuppressed = false
+        private set
+
+    /**
+     * This variable is used to store the last update time of the SDM QR PIN manager.
+     */
+    private var lastUpdateTime: Long = 0L
+
+    /**
+     * This method initializes the SDM QR PIN manager by checking the broker restrictions manager.
+     * It sets the [isDeviceOnSdmQrPinAuth], [preferredAuthMethod] and [isCameraConsentSuppressed] flags.
+     * This method is called each time `GetPreferredAuthMethodMsalBrokerOperation` is called,
+     * because the restrictions rarely change, only when a new policy is pushed to the device.
+     *
+     * @param brokerRestrictionsManager The broker restrictions manager to check the restrictions.
+     */
+    fun initializeSdmQrPinManager(brokerRestrictionsManager: IBrokerRestrictionsManager) {
+        Logger.info(TAG, "Initializing SDM QR PIN manager.")
+        val multiValueRequest = buildMultiValueRequest(
+            booleanKeys = setOf(SUPPRESS_CAMERA_CONSENT),
+            stringKeys = setOf(PREFERRED_AUTH_CONFIG)
+        )
+        val multiValues = brokerRestrictionsManager.getMultiValues(
+            brokerAppPackageName = BrokerData.prodMicrosoftAuthenticator.packageName,
+            bundleOfKeys = multiValueRequest
+        )
+        preferredAuthMethod = multiValues.getString(PREFERRED_AUTH_CONFIG)
+        if (preferredAuthMethod == PreferredAuthMethod.QR.value) {
+            isDeviceOnSdmQrPinAuth = true
+        }
+        isCameraConsentSuppressed = multiValues.getBoolean(SUPPRESS_CAMERA_CONSENT)
+        Logger.info(
+            TAG,
+            "preferredAuthMethod: $preferredAuthMethod," +
+                    " isCameraConsentSuppressed: $isCameraConsentSuppressed"
+        )
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: p3dr0rv
body: Agreed approach - I will read the value every time it is required, but I will initialize the object in the Android broker platform component.
created_at: 2025-04-29T19:50:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,89 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains functions to check"
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `brokerAndroidBrokerPlatformComponentsFactory.create` is called.
+ *
+ * Note: If this object is not initialized, values default to `false` and `null`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    private var brokerRestrictionsManager: IRestrictionsManager? = null
+
+    /**
+     * This method is used to initialize the SDM QR PIN manager with the broker restrictions manager.
+     * This is called when brokerAndroidBrokerPlatformComponentsFactory.create is called
+     * to ensure the manager is initialized with the correct broker restrictions manager.
+     */
+    fun initializeSdmQrPinManager(brokerRestrictionsManager: IRestrictionsManager) {
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: mohitc1
body: >brokerRestrictionsManager [](http://example.com/codeflow?start=34&length=25)

nit: just restrictionsManager
created_at: 2025-04-29T20:55:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,89 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains functions to check"
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `brokerAndroidBrokerPlatformComponentsFactory.create` is called.
+ *
+ * Note: If this object is not initialized, values default to `false` and `null`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    private var brokerRestrictionsManager: IRestrictionsManager? = null
+
+    /**
+     * This method is used to initialize the SDM QR PIN manager with the broker restrictions manager.
+     * This is called when brokerAndroidBrokerPlatformComponentsFactory.create is called
+     * to ensure the manager is initialized with the correct broker restrictions manager.
+     */
+    fun initializeSdmQrPinManager(brokerRestrictionsManager: IRestrictionsManager) {
+        if (this.brokerRestrictionsManager == null) {
+            this.brokerRestrictionsManager = brokerRestrictionsManager
+        }
+    }
+
+    /**
+     * This method checks if the device preferred authentication config is set.
+     */
+    fun getPreferredAuthConfig(): String? {
+        val methodTag = "$TAG:getPreferredAuthMethod"
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: mohitc1
body: >getPreferredAuthMethod [](http://example.com/codeflow?start=30&length=22)

fix tag
created_at: 2025-04-29T20:55:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,89 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains functions to check"
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `brokerAndroidBrokerPlatformComponentsFactory.create` is called.
+ *
+ * Note: If this object is not initialized, values default to `false` and `null`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    private var brokerRestrictionsManager: IRestrictionsManager? = null
+
+    /**
+     * This method is used to initialize the SDM QR PIN manager with the broker restrictions manager.
+     * This is called when brokerAndroidBrokerPlatformComponentsFactory.create is called
+     * to ensure the manager is initialized with the correct broker restrictions manager.
+     */
+    fun initializeSdmQrPinManager(brokerRestrictionsManager: IRestrictionsManager) {
+        if (this.brokerRestrictionsManager == null) {
+            this.brokerRestrictionsManager = brokerRestrictionsManager
+        }
+    }
+
+    /**
+     * This method checks if the device preferred authentication config is set.
+     */
+    fun getPreferredAuthConfig(): String? {
+        val methodTag = "$TAG:getPreferredAuthMethod"
+        val defaultValue = null
+        return brokerRestrictionsManager?.getString(
+            key = PREFERRED_AUTH_CONFIG,
+            brokerAppPackageName = BrokerData.prodMicrosoftAuthenticator.packageName,
+            defaultValue = defaultValue
+        ) ?: run {
+            Logger.warn(methodTag, "Broker restrictions manager is not initialized.")
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: mohitc1
body: > Logger.warn(methodTag, "Broker restrictions manager is not initialized.") [](http://example.com/codeflow?start=11&length=74)

I think if getString returns null, you'd get into run block, which is not correct semantically
created_at: 2025-04-29T21:02:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -70,15 +114,16 @@ class CameraPermissionRequestHandler {
 
     /**
      * Check if the given [PermissionRequest] is valid.
-     * If valid, set the current permission request and return true.
+     * If valid return true.
      * If not valid, deny the request and return false.
      * <p>
      * A request is considered valid if:
      * - The request is for the camera resource only.
      * - The request is not a repeated request (i.e., not for the same origin and resources).
-     *
+     * We can only grant or deny permissions for video capture/camera.
+     * To avoid unintentionally granting requests for not defined permissions
      */
-    fun setIfValid(request: PermissionRequest): Boolean {
+    private fun isValid(request: PermissionRequest): Boolean {
         val methodTag = "$TAG:setIfValid"
path: common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/CameraPermissionRequestHandler.kt
user: login: mohitc1
body: >setIfValid [](http://example.com/codeflow?start=30&length=10)

nit: fix tags,, will help with debugging
created_at: 2025-04-29T21:03:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,89 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains functions to check"
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `brokerAndroidBrokerPlatformComponentsFactory.create` is called.
+ *
+ * Note: If this object is not initialized, values default to `false` and `null`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    private var brokerRestrictionsManager: IRestrictionsManager? = null
+
+    /**
+     * This method is used to initialize the SDM QR PIN manager with the broker restrictions manager.
+     * This is called when brokerAndroidBrokerPlatformComponentsFactory.create is called
+     * to ensure the manager is initialized with the correct broker restrictions manager.
+     */
+    fun initializeSdmQrPinManager(brokerRestrictionsManager: IRestrictionsManager) {
+        if (this.brokerRestrictionsManager == null) {
+            this.brokerRestrictionsManager = brokerRestrictionsManager
+        }
+    }
+
+    /**
+     * This method checks if the device preferred authentication config is set.
+     */
+    fun getPreferredAuthConfig(): String? {
+        val methodTag = "$TAG:getPreferredAuthMethod"
+        val defaultValue = null
+        return brokerRestrictionsManager?.getString(
+            key = PREFERRED_AUTH_CONFIG,
+            brokerAppPackageName = BrokerData.prodMicrosoftAuthenticator.packageName,
+            defaultValue = defaultValue
+        ) ?: run {
+            Logger.warn(methodTag, "Broker restrictions manager is not initialized.")
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: p3dr0rv
body: Yes, you are right correcting this.
created_at: 2025-04-29T22:32:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -70,15 +114,16 @@ class CameraPermissionRequestHandler {
 
     /**
      * Check if the given [PermissionRequest] is valid.
-     * If valid, set the current permission request and return true.
+     * If valid return true.
      * If not valid, deny the request and return false.
      * <p>
      * A request is considered valid if:
      * - The request is for the camera resource only.
      * - The request is not a repeated request (i.e., not for the same origin and resources).
-     *
+     * We can only grant or deny permissions for video capture/camera.
+     * To avoid unintentionally granting requests for not defined permissions
      */
-    fun setIfValid(request: PermissionRequest): Boolean {
+    private fun isValid(request: PermissionRequest): Boolean {
         val methodTag = "$TAG:setIfValid"
path: common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/CameraPermissionRequestHandler.kt
user: login: p3dr0rv
body: checking tags
created_at: 2025-04-29T22:33:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,93 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains functions to check"
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `brokerAndroidBrokerPlatformComponentsFactory.create` is called.
+ *
+ * Note: If this object is not initialized, values default to `false` and `null`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    private var restrictionsManager: IRestrictionsManager? = null
+
+    /**
+     * This method is used to initialize the SDM QR PIN manager with the broker restrictions manager.
+     * This is called when brokerAndroidBrokerPlatformComponentsFactory.create is called
+     * to ensure the manager is initialized with the correct broker restrictions manager.
+     */
+    fun initializeSdmQrPinManager(restrictionsManager: IRestrictionsManager) {
+        if (this.restrictionsManager == null) {
+            this.restrictionsManager = restrictionsManager
+        }
+    }
+
+    /**
+     * This method checks if the device preferred authentication config is set.
+     */
+    fun getPreferredAuthConfig(): String? {
+        val methodTag = "$TAG:getPreferredAuthConfig"
+        val defaultValue = null
+        restrictionsManager?.let { manager ->
+            return manager.getString(
+                key = PREFERRED_AUTH_CONFIG,
+                brokerAppPackageName = BrokerData.prodMicrosoftAuthenticator.packageName,
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: somalaya
body: brokerAppPackageName is authenticator in this case?
created_at: 2025-04-30T00:00:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -97,19 +142,92 @@ class CameraPermissionRequestHandler {
             return false
         } else {
             Logger.info(methodTag, "Valid new request.")
-            setCurrentPermissionRequest(request)
             return true
         }
     }
 
     /**
-     * Set the current permission request.
+     * Check if the current permission request is a QR code pin request.
+     * <p>
+     * A request is considered a QR code pin request if:
+     * - The origin of the request is the Microsoft cloud URL.
+     * - The device is on SDM QR pin mode.
+     *
+     * @return true if the current permission request is a QR code pin request, false otherwise.
+     */
+    private fun isQrPinRequest() : Boolean {
+        return currentPermissionRequest?.origin != null
+                && MICROSOFT_CLOUD_URL.equals(currentPermissionRequest?.origin.toString(), ignoreCase = true)
+                && PreferredAuthMethod.QR.value.equals(SdmQrPinManager.getPreferredAuthConfig())
+    }
+
+    /**
+     * Handles the camera permission request for the app.
+     * If the camera permission is already granted, it will grant the permission.
+     * Otherwise, it will request the camera permission.
+     */
+    private fun defaultHandler(context: Context) {
+        val methodTag = "$TAG:defaultHandler"
+        if (appHasCameraPermission(context)) {
+            Logger.info(methodTag, "App level camera permission already granted, silent grant.")
+            grant()
+        } else {
+            requestCameraPermission()
+        }
+    }
+
+    /**
+     * Handles the camera permission request for QR code scanning.
+     * If the camera permission is already granted and the camera consent suppress is enabled,
+     * it will grant the permission. otherwise, it will explaining why the camera permission is required.
+     * If the camera permission is not granted, it will request the camera permission.
+     */
+    private fun qrPinHandler(context: Context) {
+        val  methodTag = "$TAG:handleQrPin"
+        if (appHasCameraPermission(context)) {
+            Logger.info(methodTag, "App level camera permission already granted.")
+            if (SdmQrPinManager.isCameraConsentSuppressed()) {
+                Logger.info(methodTag, "Camera consent suppress is enabled.")
+                grant()
+            } else {
+                Logger.info(methodTag, "Camera consent suppress is not enabled.")
+                showQrPinCameraRationale(context)
+            }
+        } else {
+            requestCameraPermission()
+        }
+    }
+
+    /**
+     * Determines whatever if the camera permission has been granted.
      *
-     * @param permissionRequest The permission request to set.
+     * @return true if the camera permission has been granted, false otherwise.
+     */
+    private fun appHasCameraPermission(context: Context): Boolean {
+        return (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
+                == PackageManager.PERMISSION_GRANTED)
+    }
+
+    /**
+     * Shows a dialog to the user explaining why the camera permission is required.
+     * If the user accepts the dialog, the camera permission request will be launched.
+     * If the user denies the dialog, the camera permission request will be denied.
      */
-    private fun setCurrentPermissionRequest(permissionRequest: PermissionRequest) {
-        currentPermissionRequest = permissionRequest
-        isGranted = false
+    private fun showQrPinCameraRationale(context: Context) {
+        val methodTag = "$TAG:showQrPinCameraRationale"
+        val builder = AlertDialog.Builder(context)
+        builder.setMessage(R.string.qr_code_rationale_message)
+            .setTitle(R.string.qr_code_rationale_header)
+            .setCancelable(false)
path: common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/CameraPermissionRequestHandler.kt
user: login: somalaya
body: Why is cancelable set to false?
created_at: 2025-04-30T00:09:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -97,19 +142,92 @@ class CameraPermissionRequestHandler {
             return false
         } else {
             Logger.info(methodTag, "Valid new request.")
-            setCurrentPermissionRequest(request)
             return true
         }
     }
 
     /**
-     * Set the current permission request.
+     * Check if the current permission request is a QR code pin request.
+     * <p>
+     * A request is considered a QR code pin request if:
+     * - The origin of the request is the Microsoft cloud URL.
+     * - The device is on SDM QR pin mode.
+     *
+     * @return true if the current permission request is a QR code pin request, false otherwise.
+     */
+    private fun isQrPinRequest() : Boolean {
+        return currentPermissionRequest?.origin != null
+                && MICROSOFT_CLOUD_URL.equals(currentPermissionRequest?.origin.toString(), ignoreCase = true)
+                && PreferredAuthMethod.QR.value.equals(SdmQrPinManager.getPreferredAuthConfig())
+    }
+
+    /**
+     * Handles the camera permission request for the app.
+     * If the camera permission is already granted, it will grant the permission.
+     * Otherwise, it will request the camera permission.
+     */
+    private fun defaultHandler(context: Context) {
+        val methodTag = "$TAG:defaultHandler"
+        if (appHasCameraPermission(context)) {
+            Logger.info(methodTag, "App level camera permission already granted, silent grant.")
+            grant()
+        } else {
+            requestCameraPermission()
+        }
+    }
+
+    /**
+     * Handles the camera permission request for QR code scanning.
+     * If the camera permission is already granted and the camera consent suppress is enabled,
+     * it will grant the permission. otherwise, it will explaining why the camera permission is required.
+     * If the camera permission is not granted, it will request the camera permission.
+     */
+    private fun qrPinHandler(context: Context) {
+        val  methodTag = "$TAG:handleQrPin"
+        if (appHasCameraPermission(context)) {
+            Logger.info(methodTag, "App level camera permission already granted.")
+            if (SdmQrPinManager.isCameraConsentSuppressed()) {
+                Logger.info(methodTag, "Camera consent suppress is enabled.")
+                grant()
+            } else {
+                Logger.info(methodTag, "Camera consent suppress is not enabled.")
+                showQrPinCameraRationale(context)
+            }
+        } else {
+            requestCameraPermission()
+        }
+    }
+
+    /**
+     * Determines whatever if the camera permission has been granted.
      *
-     * @param permissionRequest The permission request to set.
+     * @return true if the camera permission has been granted, false otherwise.
+     */
+    private fun appHasCameraPermission(context: Context): Boolean {
+        return (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
+                == PackageManager.PERMISSION_GRANTED)
+    }
+
+    /**
+     * Shows a dialog to the user explaining why the camera permission is required.
+     * If the user accepts the dialog, the camera permission request will be launched.
+     * If the user denies the dialog, the camera permission request will be denied.
      */
-    private fun setCurrentPermissionRequest(permissionRequest: PermissionRequest) {
-        currentPermissionRequest = permissionRequest
-        isGranted = false
+    private fun showQrPinCameraRationale(context: Context) {
+        val methodTag = "$TAG:showQrPinCameraRationale"
+        val builder = AlertDialog.Builder(context)
+        builder.setMessage(R.string.qr_code_rationale_message)
+            .setTitle(R.string.qr_code_rationale_header)
+            .setCancelable(false)
path: common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/CameraPermissionRequestHandler.kt
user: login: p3dr0rv
body: In the showQrPinCameraRationale method, the setCancelable(false) is used to ensure that the dialog cannot be dismissed by tapping outside the dialog or pressing the back button. This is likely done to make sure the user explicitly chooses one of the provided options (allow or block) for granting or denying the camera permission.
created_at: 2025-04-30T00:11:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,93 @@
+// Copyright (c) Microsoft Corporation.
+// All rights reserved.
+//
+// This code is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package com.microsoft.identity.common.internal.broker
+
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.PREFERRED_AUTH_CONFIG
+import com.microsoft.identity.common.internal.broker.IRestrictionsManager.BrokerRestrictionsManagerKeys.SUPPRESS_CAMERA_CONSENT
+import com.microsoft.identity.common.logging.Logger
+
+/**
+ * Manages the SDM QR PIN mode settings for the device.
+ *
+ * This object contains functions to check"
+ * - Whether camera consent should be suppressed.
+ * - The preferred authentication method for the device.
+ *
+ * It is initialized each time `brokerAndroidBrokerPlatformComponentsFactory.create` is called.
+ *
+ * Note: If this object is not initialized, values default to `false` and `null`,
+ * meaning the device is not in SDM QR PIN mode.
+ */
+object SdmQrPinManager {
+
+    private const val TAG = "SdmQrPinManager"
+
+    private var restrictionsManager: IRestrictionsManager? = null
+
+    /**
+     * This method is used to initialize the SDM QR PIN manager with the broker restrictions manager.
+     * This is called when brokerAndroidBrokerPlatformComponentsFactory.create is called
+     * to ensure the manager is initialized with the correct broker restrictions manager.
+     */
+    fun initializeSdmQrPinManager(restrictionsManager: IRestrictionsManager) {
+        if (this.restrictionsManager == null) {
+            this.restrictionsManager = restrictionsManager
+        }
+    }
+
+    /**
+     * This method checks if the device preferred authentication config is set.
+     */
+    fun getPreferredAuthConfig(): String? {
+        val methodTag = "$TAG:getPreferredAuthConfig"
+        val defaultValue = null
+        restrictionsManager?.let { manager ->
+            return manager.getString(
+                key = PREFERRED_AUTH_CONFIG,
+                brokerAppPackageName = BrokerData.prodMicrosoftAuthenticator.packageName,
path: common/src/main/java/com/microsoft/identity/common/internal/broker/SdmQrPinManager.kt
user: login: p3dr0rv
body: yes, improving doc
created_at: 2025-04-30T00:12:25Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-25T03:52:53Z
body: ❌ Work item link check failed. Description does not contain AB#{ID}.

[Click here](https://learn.microsoft.com/en-us/azure/devops/boards/github/link-to-from-github?view=azure-devops#use-ab-mention-to-link-from-github-to-azure-boards-work-items) to Learn more.

<!-- code: lcc-404 -->
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-25T23:06:47Z
body: ✅ Work item link check complete. Description contains link AB#3121976 to an Azure Boards work item.

<!-- code: lcc-200 -->
author_association: NONE