diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java index 23776ea6e26805..685dbf2fb6426e 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java @@ -67,11 +67,8 @@ public void handleCommissioningButtonClicked(DiscoveredNodeData commissioner) { @Override public void handleConnectionButtonClicked( - CastingPlayer castingPlayer, Boolean useCommissionerGeneratedPasscode) { - Log.i( - TAG, - "MainActivity.handleConnectionButtonClicked() useCommissionerGeneratedPasscode: " - + useCommissionerGeneratedPasscode); + CastingPlayer castingPlayer, boolean useCommissionerGeneratedPasscode) { + Log.i(TAG, "MainActivity.handleConnectionButtonClicked()"); showFragment( ConnectionExampleFragment.newInstance(castingPlayer, useCommissionerGeneratedPasscode)); } @@ -83,37 +80,34 @@ public void handleCommissioningComplete() { @Override public void handleConnectionComplete( - CastingPlayer castingPlayer, Boolean useCommissionerGeneratedPasscode) { - Log.i( - TAG, - "MainActivity.handleConnectionComplete() useCommissionerGeneratedPasscode: " - + useCommissionerGeneratedPasscode); + CastingPlayer castingPlayer, boolean useCommissionerGeneratedPasscode) { + Log.i(TAG, "MainActivity.handleConnectionComplete()"); showFragment( ActionSelectorFragment.newInstance(castingPlayer, useCommissionerGeneratedPasscode)); } @Override public void handleContentLauncherLaunchURLSelected( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample) { + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode) { showFragment( ContentLauncherLaunchURLExampleFragment.newInstance( - selectedCastingPlayer, commissionerGeneratedPasscodeExample)); + selectedCastingPlayer, useCommissionerGeneratedPasscode)); } @Override public void handleApplicationBasicReadVendorIDSelected( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample) { + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode) { showFragment( ApplicationBasicReadVendorIDExampleFragment.newInstance( - selectedCastingPlayer, commissionerGeneratedPasscodeExample)); + selectedCastingPlayer, useCommissionerGeneratedPasscode)); } @Override public void handleMediaPlaybackSubscribeToCurrentStateSelected( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample) { + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode) { showFragment( MediaPlaybackSubscribeToCurrentStateExampleFragment.newInstance( - selectedCastingPlayer, commissionerGeneratedPasscodeExample)); + selectedCastingPlayer, useCommissionerGeneratedPasscode)); } @Override diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ActionSelectorFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ActionSelectorFragment.java index 0b6504d716d0d5..a931d1ff3baf44 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ActionSelectorFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ActionSelectorFragment.java @@ -31,7 +31,7 @@ public class ActionSelectorFragment extends Fragment { private static final String TAG = ActionSelectorFragment.class.getSimpleName(); private final CastingPlayer selectedCastingPlayer; - private final Boolean commissionerGeneratedPasscodeExample; + private final boolean useCommissionerGeneratedPasscode; private View.OnClickListener selectContentLauncherButtonClickListener; private View.OnClickListener selectApplicationBasicButtonClickListener; @@ -39,9 +39,9 @@ public class ActionSelectorFragment extends Fragment { private View.OnClickListener disconnectButtonClickListener; public ActionSelectorFragment( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample) { + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode) { this.selectedCastingPlayer = selectedCastingPlayer; - this.commissionerGeneratedPasscodeExample = commissionerGeneratedPasscodeExample; + this.useCommissionerGeneratedPasscode = useCommissionerGeneratedPasscode; } /** @@ -49,13 +49,13 @@ public ActionSelectorFragment( * parameters. * * @param selectedCastingPlayer CastingPlayer that the casting app connected to - * @param commissionerGeneratedPasscodeExample Boolean indicating whether this CastingPlayer was - * commissioned using the Commissioner-Generated passcode commissioning flow + * @param useCommissionerGeneratedPasscode Boolean indicating whether this CastingPlayer was + * commissioned using the Commissioner-Generated passcode commissioning flow. * @return A new instance of fragment SelectActionFragment. */ public static ActionSelectorFragment newInstance( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample) { - return new ActionSelectorFragment(selectedCastingPlayer, commissionerGeneratedPasscodeExample); + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode) { + return new ActionSelectorFragment(selectedCastingPlayer, useCommissionerGeneratedPasscode); } @Override @@ -71,19 +71,19 @@ public View onCreateView( v -> { Log.d(TAG, "handle() called on selectContentLauncherButtonClickListener"); callback.handleContentLauncherLaunchURLSelected( - selectedCastingPlayer, commissionerGeneratedPasscodeExample); + selectedCastingPlayer, useCommissionerGeneratedPasscode); }; this.selectApplicationBasicButtonClickListener = v -> { Log.d(TAG, "handle() called on selectApplicationBasicButtonClickListener"); callback.handleApplicationBasicReadVendorIDSelected( - selectedCastingPlayer, commissionerGeneratedPasscodeExample); + selectedCastingPlayer, useCommissionerGeneratedPasscode); }; this.selectMediaPlaybackButtonClickListener = v -> { Log.d(TAG, "handle() called on selectMediaPlaybackButtonClickListener"); callback.handleMediaPlaybackSubscribeToCurrentStateSelected( - selectedCastingPlayer, commissionerGeneratedPasscodeExample); + selectedCastingPlayer, useCommissionerGeneratedPasscode); }; this.disconnectButtonClickListener = @@ -117,15 +117,15 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { public interface Callback { /** Notifies listener to trigger transition on selection of Content Launcher cluster */ void handleContentLauncherLaunchURLSelected( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample); + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode); /** Notifies listener to trigger transition on selection of Application Basic cluster */ void handleApplicationBasicReadVendorIDSelected( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample); + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode); /** Notifies listener to trigger transition on selection of Media PLayback cluster */ void handleMediaPlaybackSubscribeToCurrentStateSelected( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample); + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode); /** Notifies listener to trigger transition on click of the Disconnect button */ void handleDisconnect(); diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ApplicationBasicReadVendorIDExampleFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ApplicationBasicReadVendorIDExampleFragment.java index 6fdcb600a30fb3..b64d10ce811332 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ApplicationBasicReadVendorIDExampleFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ApplicationBasicReadVendorIDExampleFragment.java @@ -37,29 +37,32 @@ public class ApplicationBasicReadVendorIDExampleFragment extends Fragment { private static final String TAG = ApplicationBasicReadVendorIDExampleFragment.class.getSimpleName(); + private static final int DEFAULT_ENDPOINT_ID_FOR_CGP_FLOW = 1; private final CastingPlayer selectedCastingPlayer; - private final Boolean commissionerGeneratedPasscodeExample; + private final boolean useCommissionerGeneratedPasscode; private View.OnClickListener readButtonClickListener; public ApplicationBasicReadVendorIDExampleFragment( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample) { + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode) { this.selectedCastingPlayer = selectedCastingPlayer; - this.commissionerGeneratedPasscodeExample = commissionerGeneratedPasscodeExample; + this.useCommissionerGeneratedPasscode = useCommissionerGeneratedPasscode; } /** * Use this factory method to create a new instance of this fragment using the provided * parameters. * - * @param selectedCastingPlayer CastingPlayer that the casting app connected to + * @param selectedCastingPlayer CastingPlayer that the casting app connected to. + * @param useCommissionerGeneratedPasscode Boolean indicating whether this CastingPlayer was + * commissioned using the Commissioner-Generated Passcode (CGP) commissioning flow. * @return A new instance of fragment ApplicationBasicReadVendorIDExampleFragment. */ public static ApplicationBasicReadVendorIDExampleFragment newInstance( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample) { + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode) { return new ApplicationBasicReadVendorIDExampleFragment( - selectedCastingPlayer, commissionerGeneratedPasscodeExample); + selectedCastingPlayer, useCommissionerGeneratedPasscode); } @Override @@ -73,8 +76,10 @@ public View onCreateView( this.readButtonClickListener = v -> { Endpoint endpoint; - if (commissionerGeneratedPasscodeExample) { - endpoint = EndpointSelectorExample.selectFirstEndpoint(selectedCastingPlayer); + if (useCommissionerGeneratedPasscode) { + endpoint = + EndpointSelectorExample.selectEndpointById( + selectedCastingPlayer, DEFAULT_ENDPOINT_ID_FOR_CGP_FLOW); } else { endpoint = EndpointSelectorExample.selectFirstEndpointByVID(selectedCastingPlayer); } diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ConnectionExampleFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ConnectionExampleFragment.java index ae5e60e2a0c7d4..31075df71fb432 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ConnectionExampleFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ConnectionExampleFragment.java @@ -30,11 +30,9 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import com.R; -import com.matter.casting.core.CastingApp; import com.matter.casting.core.CastingPlayer; import com.matter.casting.support.CommissionerDeclaration; import com.matter.casting.support.ConnectionCallbacks; -import com.matter.casting.support.DataProvider; import com.matter.casting.support.IdentificationDeclarationOptions; import com.matter.casting.support.MatterCallback; import com.matter.casting.support.MatterError; @@ -49,17 +47,18 @@ public class ConnectionExampleFragment extends Fragment { private static final short MIN_CONNECTION_TIMEOUT_SEC = 3 * 60; private static final Integer DESIRED_TARGET_APP_VENDOR_ID = 65521; // Use this Target Content Application Vendor ID, configured on the tv-app, to demonstrate the - // Commissioner-Generated passcode commissioning flow. + // CastingPlayer/Commissioner-Generated passcode commissioning flow. private static final Integer DESIRED_TARGET_APP_VENDOR_ID_FOR_CGP_FLOW = 1111; - private static final String DEFAULT_COMMISSIONER_GENERATED_PASSCODE = "12345678"; + private static final String DEFAULT_COMMISSIONER_GENERATED_PASSCODE_STRING = "12345678"; + private static final int DEFAULT_COMMISSIONER_GENERATED_PASSCODE_INT = 12345678; private static final int DEFAULT_DISCRIMINATOR_FOR_CGP_FLOW = 0; private final CastingPlayer targetCastingPlayer; - private final Boolean useCommissionerGeneratedPasscode; + private final boolean useCommissionerGeneratedPasscode; private TextView connectionFragmentStatusTextView; private Button connectionFragmentNextButton; public ConnectionExampleFragment( - CastingPlayer targetCastingPlayer, Boolean useCommissionerGeneratedPasscode) { + CastingPlayer targetCastingPlayer, boolean useCommissionerGeneratedPasscode) { Log.i( TAG, "ConnectionExampleFragment() Target CastingPlayer ID: " @@ -106,12 +105,12 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { connectionFragmentStatusTextView.setText( "Verifying or establishing connection with Casting Player with device name: " + targetCastingPlayer.getDeviceName() - + "\n\nAttempting Commissioner-Generated passcode commissioning."); + + "\n\nAttempting CastingPlayer/Commissioner-Generated passcode commissioning."); } else { connectionFragmentStatusTextView.setText( "Verifying or establishing connection with Casting Player with device name: " + targetCastingPlayer.getDeviceName() - + "\nCommissionee-Generated Setup Passcode: " + + "\nClient/Commissionee-Generated Setup Passcode: " + InitializationExample.commissionableDataProvider.get().getSetupPasscode() + "\nDiscriminator: " + InitializationExample.commissionableDataProvider.get().getDiscriminator()); @@ -135,7 +134,7 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { targetAppInfo.vendorId = DESIRED_TARGET_APP_VENDOR_ID; if (useCommissionerGeneratedPasscode) { - idOptions.mCommissionerPasscode = true; + idOptions.commissionerPasscode = true; targetAppInfo.vendorId = DESIRED_TARGET_APP_VENDOR_ID_FOR_CGP_FLOW; Log.d( TAG, @@ -186,7 +185,8 @@ public void handle(MatterError err) { }, null); - // CommissionerDeclaration is only needed for the Commissioner-Generated passcode + // CommissionerDeclaration is only needed for the CastingPlayer/Commissioner-Generated + // passcode // commissioning flow. if (useCommissionerGeneratedPasscode) { connectionCallbacks.onCommissionerDeclaration = @@ -231,21 +231,12 @@ public void handle(CommissionerDeclaration cd) { private void displayPasscodeInputDialog(Context context) { AlertDialog.Builder builder = new AlertDialog.Builder(context); - String title = "Enter the Commissioner-Generated Passcode"; - String instructions = - "Input the Commissioner-Generated passcode displayed on the CastingPlayer UX, or use the default provided (12345678)."; - LayoutInflater inflater = LayoutInflater.from(context); View dialogView = inflater.inflate(R.layout.custom_passcode_dialog, null); - TextView titleTextView = dialogView.findViewById(R.id.dialog_title); - TextView instructionsTextView = dialogView.findViewById(R.id.dialog_instructions); - titleTextView.setText(title); - instructionsTextView.setText(instructions); - // Set up the input dialog with the default passcode final EditText input = dialogView.findViewById(R.id.passcode_input); - input.setText(DEFAULT_COMMISSIONER_GENERATED_PASSCODE); + input.setText(DEFAULT_COMMISSIONER_GENERATED_PASSCODE_STRING); // Set up the buttons builder.setPositiveButton( @@ -256,50 +247,70 @@ public void onClick(DialogInterface dialog, int which) { String passcode = input.getText().toString(); Log.i( TAG, - "displayPasscodeInputDialog() User entered Commissioner-Generated passcode: " + "displayPasscodeInputDialog() User entered CastingPlayer/Commissioner-Generated passcode: " + passcode); // Display the user entered passcode on the screen connectionFragmentStatusTextView.setText( - "Continue Connecting with user entered Commissioner-Generated passcode: " + "Continue Connecting with user entered CastingPlayer/Commissioner-Generated passcode: " + passcode + "\n\n"); - long passcodeLongValue = 12345678; + long passcodeLongValue = DEFAULT_COMMISSIONER_GENERATED_PASSCODE_INT; try { passcodeLongValue = Long.parseLong(passcode); + Log.i( + TAG, + "displayPasscodeInputDialog() User entered CastingPlayer/Commissioner-Generated passcode: " + + passcodeLongValue); } catch (NumberFormatException nfe) { + Log.e( + TAG, + "displayPasscodeInputDialog()User entered CastingPlayer/Commissioner-Generated passcode is not a valid integer. NumberFormatException: " + + nfe); + connectionFragmentStatusTextView.setText( + "User entered CastingPlayer/Commissioner-Generated passcode is not a valid integer: " + + passcode + + "\n\n"); } // Update the CommissionableData DataProvider and AndroidChipPlatform with the user - // entered Commissioner-Generated setup passcode. This is mandatory for - // Commissioner-Generated passcode commissioning. - ((DataProvider) InitializationExample.commissionableDataProvider) - .updateCommissionableDataSetupPasscode( - passcodeLongValue, DEFAULT_DISCRIMINATOR_FOR_CGP_FLOW); - MatterError err = - CastingApp.getInstance().updateAndroidChipPlatformWithCommissionableData(); + // entered CastingPlayer/Commissioner-Generated setup passcode. This is mandatory for + // Commissioner-Generated passcode commissioning since the commissioning session's PAKE + // verifier needs to be updated with the entered passcode. + InitializationExample.commissionableDataProvider.updateCommissionableDataSetupPasscode( + passcodeLongValue, DEFAULT_DISCRIMINATOR_FOR_CGP_FLOW); + + Log.i(TAG, "displayPasscodeInputDialog() calling continueConnecting()"); + connectionFragmentStatusTextView = + getView().findViewById(R.id.connectionFragmentStatusText); + connectionFragmentStatusTextView.setText( + "Continuing to connect with Casting Player with device name: " + + targetCastingPlayer.getDeviceName() + + "\nCastingPlayer/Commissioner-Generated Setup Passcode: " + + InitializationExample.commissionableDataProvider.get().getSetupPasscode() + + "\nDiscriminator: " + + InitializationExample.commissionableDataProvider.get().getDiscriminator()); + + MatterError err = targetCastingPlayer.continueConnecting(); if (err.hasError()) { - connectionFragmentStatusTextView.setText( - "displayPasscodeInputDialog() Casting Player connection failed due to: " - + err - + "\n\n"); - Log.e(TAG, "displayPasscodeInputDialog() calling stopConnecting() due to: " + err); - targetCastingPlayer.stopConnecting(); - } else { - Log.i(TAG, "displayPasscodeInputDialog() calling continueConnecting()"); - connectionFragmentStatusTextView = - getView().findViewById(R.id.connectionFragmentStatusText); - connectionFragmentStatusTextView.setText( - "Continuing connection with Casting Player with device name: " - + targetCastingPlayer.getDeviceName() - + "\nCommissioner-Generated Setup Passcode: " - + InitializationExample.commissionableDataProvider.get().getSetupPasscode() - + "\nDiscriminator: " - + InitializationExample.commissionableDataProvider.get().getDiscriminator()); - - targetCastingPlayer.continueConnecting(); + MatterError finalErr = err; + getActivity() + .runOnUiThread( + () -> { + connectionFragmentStatusTextView.setText( + "Casting Player connection failed due to: " + finalErr + "\n\n"); + }); + Log.e( + TAG, + "displayPasscodeInputDialog() continueConnecting() failed, calling stopConnecting() due to: " + + err); + // Attempt to cancel the connection attempt with the CastingPlayer/Commissioner. + err = targetCastingPlayer.stopConnecting(); + if (err.hasError()) { + Log.e(TAG, "displayPasscodeInputDialog() stopConnecting() failed due to: " + err); + } } } }); @@ -311,10 +322,13 @@ public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) { Log.i( TAG, - "displayPasscodeInputDialog() user cancelled the Commissioner-Generated Passcode input dialog."); + "displayPasscodeInputDialog() user cancelled the CastingPlayer/Commissioner-Generated Passcode input dialog. Calling stopConnecting()"); connectionFragmentStatusTextView.setText( "Connection attempt with Casting Player cancelled by the user, route back to exit. \n\n"); - targetCastingPlayer.stopConnecting(); + MatterError err = targetCastingPlayer.stopConnecting(); + if (err.hasError()) { + Log.e(TAG, "displayPasscodeInputDialog() stopConnecting() failed due to: " + err); + } dialog.cancel(); } }); @@ -331,6 +345,6 @@ public void onClick(DialogInterface dialog, int which) { public interface Callback { /** Notifies listener to trigger transition on completion of connection */ void handleConnectionComplete( - CastingPlayer castingPlayer, Boolean useCommissionerGeneratedPasscode); + CastingPlayer castingPlayer, boolean useCommissionerGeneratedPasscode); } } diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ContentLauncherLaunchURLExampleFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ContentLauncherLaunchURLExampleFragment.java index cdae4c7e2a81ec..e1cfc4a456112b 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ContentLauncherLaunchURLExampleFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ContentLauncherLaunchURLExampleFragment.java @@ -37,29 +37,32 @@ public class ContentLauncherLaunchURLExampleFragment extends Fragment { private static final String TAG = ContentLauncherLaunchURLExampleFragment.class.getSimpleName(); private static final Integer SAMPLE_ENDPOINT_VID = 65521; + private static final int DEFAULT_ENDPOINT_ID_FOR_CGP_FLOW = 1; private final CastingPlayer selectedCastingPlayer; - private final Boolean commissionerGeneratedPasscodeExample; + private final boolean useCommissionerGeneratedPasscode; private View.OnClickListener launchUrlButtonClickListener; public ContentLauncherLaunchURLExampleFragment( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample) { + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode) { this.selectedCastingPlayer = selectedCastingPlayer; - this.commissionerGeneratedPasscodeExample = commissionerGeneratedPasscodeExample; + this.useCommissionerGeneratedPasscode = useCommissionerGeneratedPasscode; } /** * Use this factory method to create a new instance of this fragment using the provided * parameters. * - * @param selectedCastingPlayer CastingPlayer that the casting app connected to + * @param selectedCastingPlayer CastingPlayer that the casting app connected to. + * @param useCommissionerGeneratedPasscode Boolean indicating whether this CastingPlayer was + * commissioned using the Commissioner-Generated Passcode (CGP) commissioning flow. * @return A new instance of fragment ContentLauncherLaunchURLExampleFragment. */ public static ContentLauncherLaunchURLExampleFragment newInstance( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample) { + CastingPlayer selectedCastingPlayer, Boolean useCommissionerGeneratedPasscode) { return new ContentLauncherLaunchURLExampleFragment( - selectedCastingPlayer, commissionerGeneratedPasscodeExample); + selectedCastingPlayer, useCommissionerGeneratedPasscode); } @Override @@ -73,8 +76,10 @@ public View onCreateView( this.launchUrlButtonClickListener = v -> { Endpoint endpoint; - if (commissionerGeneratedPasscodeExample) { - endpoint = EndpointSelectorExample.selectFirstEndpoint(selectedCastingPlayer); + if (useCommissionerGeneratedPasscode) { + endpoint = + EndpointSelectorExample.selectEndpointById( + selectedCastingPlayer, DEFAULT_ENDPOINT_ID_FOR_CGP_FLOW); } else { endpoint = EndpointSelectorExample.selectFirstEndpointByVID(selectedCastingPlayer); } diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/DiscoveryExampleFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/DiscoveryExampleFragment.java index 69160b99745741..3dca2320b8924c 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/DiscoveryExampleFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/DiscoveryExampleFragment.java @@ -222,7 +222,7 @@ public void onPause() { public interface Callback { /** Notifies listener of Connection Button click. */ void handleConnectionButtonClicked( - CastingPlayer castingPlayer, Boolean useCommissionerGeneratedPasscode); + CastingPlayer castingPlayer, boolean useCommissionerGeneratedPasscode); } private boolean startDiscovery() { diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/EndpointSelectorExample.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/EndpointSelectorExample.java index 5a042cbb787e77..e3775835104c06 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/EndpointSelectorExample.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/EndpointSelectorExample.java @@ -19,30 +19,33 @@ public static Endpoint selectFirstEndpointByVID(CastingPlayer selectedCastingPla if (selectedCastingPlayer != null) { List endpoints = selectedCastingPlayer.getEndpoints(); if (endpoints == null) { - Log.e(TAG, "No Endpoints found on CastingPlayer"); + Log.e(TAG, "selectFirstEndpointByVID() No Endpoints found on CastingPlayer"); } else { endpoint = endpoints .stream() .filter(e -> SAMPLE_ENDPOINT_VID.equals(e.getVendorId())) .findFirst() - .get(); + .orElse(null); } } return endpoint; } /** - * Returns the first Endpoint in the list of Endpoints associated with the selectedCastingPlayer. + * Returns the Endpoint with the desired endpoint Id in the list of Endpoints associated with the + * selectedCastingPlayer. */ - public static Endpoint selectFirstEndpoint(CastingPlayer selectedCastingPlayer) { + public static Endpoint selectEndpointById( + CastingPlayer selectedCastingPlayer, int desiredEndpointId) { Endpoint endpoint = null; if (selectedCastingPlayer != null) { List endpoints = selectedCastingPlayer.getEndpoints(); if (endpoints == null || endpoints.isEmpty()) { - Log.e(TAG, "No Endpoints found on CastingPlayer"); + Log.e(TAG, "selectEndpointById() No Endpoints found on CastingPlayer"); } else { - endpoint = endpoints.get(0); + endpoint = + endpoints.stream().filter(e -> desiredEndpointId == e.getId()).findFirst().orElse(null); } } return endpoint; diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/InitializationExample.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/InitializationExample.java index 3882adec759c8a..6cae9ab8326474 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/InitializationExample.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/InitializationExample.java @@ -52,33 +52,32 @@ public byte[] get() { * DataProvider implementation for the Commissioning Data used by the SDK when the CastingApp goes * through commissioning */ - public static DataProvider commissionableDataProvider = - new DataProvider() { - CommissionableData commissionableData = - new CommissionableData(DUMMY_SETUP_PASSCODE, DUMMY_DISCRIMINATOR); + public static class CommissionableDataProvider implements DataProvider { + CommissionableData commissionableData = + new CommissionableData(DUMMY_SETUP_PASSCODE, DUMMY_DISCRIMINATOR); - @Override - public CommissionableData get() { - return commissionableData; - } + @Override + public CommissionableData get() { + return commissionableData; + } - /** - * Must be implemented in the CommissionableData DataProvider if the Commissioner-Generated - * passcode commissioning flow is going to be used. In this flow, the setup passcode is - * generated by the CastingPlayer and entered by the user in the tv-casting-app CX. Once it - * is obtained, this function should be called with the Commissioner-Generated passcode to - * update the CommissionableData DataProvider in AppParameters. The client is also - * responsible for calling CastingApp::updateAndroidChipPlatformWithCommissionableData() to - * update the data provider set which was previously set in the AppParameters and - * AndroidChipPlatform at initialization time. - */ - @Override - public void updateCommissionableDataSetupPasscode(long setupPasscode, int discriminator) { - Log.i(TAG, "DataProvider::updateCommissionableDataSetupPasscode()"); - commissionableData.setSetupPasscode(setupPasscode); - commissionableData.setDiscriminator(discriminator); - } - }; + /** + * Must be implemented in the CommissionableData DataProvider if the + * CastingPlayer/Commissioner-Generated passcode commissioning flow is going to be used. In this + * flow, the setup passcode is generated by the Commissioner and entered by the user in the + * tv-casting-app CX. Once it is obtained, this function should be called with the + * Commissioner-Generated passcode to update the CommissionableData DataProvider in + * AppParameters. + */ + public void updateCommissionableDataSetupPasscode(long setupPasscode, int discriminator) { + Log.i(TAG, "DataProvider::updateCommissionableDataSetupPasscode()"); + commissionableData.setSetupPasscode(setupPasscode); + commissionableData.setDiscriminator(discriminator); + } + }; + + public static CommissionableDataProvider commissionableDataProvider = + new CommissionableDataProvider(); /** * DACProvider implementation for the Device Attestation Credentials required at the time of diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/MediaPlaybackSubscribeToCurrentStateExampleFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/MediaPlaybackSubscribeToCurrentStateExampleFragment.java index b2e5ba6e3c6714..cd5bbba14af2ed 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/MediaPlaybackSubscribeToCurrentStateExampleFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/MediaPlaybackSubscribeToCurrentStateExampleFragment.java @@ -40,30 +40,33 @@ public class MediaPlaybackSubscribeToCurrentStateExampleFragment extends Fragment { private static final String TAG = MediaPlaybackSubscribeToCurrentStateExampleFragment.class.getSimpleName(); + private static final int DEFAULT_ENDPOINT_ID_FOR_CGP_FLOW = 1; private final CastingPlayer selectedCastingPlayer; - private final Boolean commissionerGeneratedPasscodeExample; + private final boolean useCommissionerGeneratedPasscode; private View.OnClickListener subscribeButtonClickListener; private View.OnClickListener shutdownSubscriptionsButtonClickListener; public MediaPlaybackSubscribeToCurrentStateExampleFragment( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample) { + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode) { this.selectedCastingPlayer = selectedCastingPlayer; - this.commissionerGeneratedPasscodeExample = commissionerGeneratedPasscodeExample; + this.useCommissionerGeneratedPasscode = useCommissionerGeneratedPasscode; } /** * Use this factory method to create a new instance of this fragment using the provided * parameters. * - * @param selectedCastingPlayer CastingPlayer that the casting app connected to + * @param selectedCastingPlayer CastingPlayer that the casting app connected to. + * @param useCommissionerGeneratedPasscode Boolean indicating whether this CastingPlayer was + * commissioned using the Commissioner-Generated Passcode (CGP) commissioning flow. * @return A new instance of fragment MediaPlaybackSubscribeToCurrentStateExampleFragment. */ public static MediaPlaybackSubscribeToCurrentStateExampleFragment newInstance( - CastingPlayer selectedCastingPlayer, Boolean commissionerGeneratedPasscodeExample) { + CastingPlayer selectedCastingPlayer, boolean useCommissionerGeneratedPasscode) { return new MediaPlaybackSubscribeToCurrentStateExampleFragment( - selectedCastingPlayer, commissionerGeneratedPasscodeExample); + selectedCastingPlayer, useCommissionerGeneratedPasscode); } @Override @@ -75,8 +78,10 @@ public void onCreate(Bundle savedInstanceState) { public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Endpoint endpoint; - if (commissionerGeneratedPasscodeExample) { - endpoint = EndpointSelectorExample.selectFirstEndpoint(selectedCastingPlayer); + if (useCommissionerGeneratedPasscode) { + endpoint = + EndpointSelectorExample.selectEndpointById( + selectedCastingPlayer, DEFAULT_ENDPOINT_ID_FOR_CGP_FLOW); } else { endpoint = EndpointSelectorExample.selectFirstEndpointByVID(selectedCastingPlayer); } diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/CastingPlayer.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/CastingPlayer.java index 425fc237e5cce1..95df588e23494a 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/CastingPlayer.java +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/CastingPlayer.java @@ -23,7 +23,7 @@ import java.util.List; /** - * The CastingPlayer interface defines a Matter commissioner that is able to play media to a + * The CastingPlayer interface defines a Matter Commissioner that is able to play media to a * physical output or to a display screen which is part of the device (e.g. TV). It is discovered on * the local network using Matter Commissioner discovery over DNS. It contains all the information * about the service discovered/resolved. @@ -80,9 +80,9 @@ public interface CastingPlayer { * a CommissionerDeclaration message from the Commissioner. This callback is needed to support * UDC features where a reply from the Commissioner is expected. It provides information * indicating the Commissioner’s pre-commissioning state. - *

For example: During Commissioner-Generated passcode commissioning, the Commissioner - * replies with a CommissionerDeclaration message with PasscodeDialogDisplayed and - * CommissionerPasscode set to true. Given these Commissioner state details, the client is + *

For example: During CastingPlayer/Commissioner-Generated passcode commissioning, the + * Commissioner replies with a CommissionerDeclaration message with PasscodeDialogDisplayed + * and CommissionerPasscode set to true. Given these Commissioner state details, the client is * expected to perform some actions, detailed in the continueConnecting() API below, and then * call the continueConnecting() API to complete the process. * @param commissioningWindowTimeoutSec (Optional) time (in sec) to keep the commissioning window @@ -90,15 +90,15 @@ public interface CastingPlayer { * @param idOptions (Optional) Parameters in the IdentificationDeclaration message sent by the * Commissionee to the Commissioner. These parameters specify the information relating to the * requested commissioning session. - *

For example: To invoke the Commissioner-Generated passcode commissioning flow, the - * client would call this API with IdentificationDeclarationOptions containing + *

For example: To invoke the CastingPlayer/Commissioner-Generated passcode commissioning + * flow, the client would call this API with IdentificationDeclarationOptions containing * CommissionerPasscode set to true. See IdentificationDeclarationOptions.java for a complete * list of optional parameters. *

Furthermore, attributes (such as VendorId) describe the TargetApp that the client wants * to interact with after commissioning. If this value is passed in, * verifyOrEstablishConnection() will force UDC, in case the desired TargetApp is not found in * the on-device CastingStore. - * @return MatterError - Matter.NO_ERROR if request submitted successfully, otherwise a + * @return MatterError - MatterError.NO_ERROR if request submitted successfully, otherwise a * MatterError object corresponding to the error. */ MatterError verifyOrEstablishConnection( @@ -111,17 +111,17 @@ MatterError verifyOrEstablishConnection( * * @param connectionCallbacks contains the onSuccess (Required), onFailure (Required) and * onCommissionerDeclaration (Optional) callbacks defiend in ConnectCallbacks.java. - * @return MatterError - Matter.NO_ERROR if request submitted successfully, otherwise a + * @return MatterError - MatterError.NO_ERROR if request submitted successfully, otherwise a * MatterError object corresponding to the error. */ MatterError verifyOrEstablishConnection(ConnectionCallbacks connectionCallbacks); /** - * @brief This is a continuation of the Commissioner-Generated passcode commissioning flow started - * via the verifyOrEstablishConnection() API above. It continues the UDC process by sending a - * second IdentificationDeclaration message to Commissioner containing CommissionerPasscode - * and CommissionerPasscodeReady set to true. At this point it is assumed that the following - * have occurred: + * @brief This is a continuation of the CastingPlayer/Commissioner-Generated passcode + * commissioning flow started via the verifyOrEstablishConnection() API above. It continues + * the UDC process by sending a second IdentificationDeclaration message to Commissioner + * containing CommissionerPasscode and CommissionerPasscodeReady set to true. At this point it + * is assumed that the following have occurred: *

1. Client (Commissionee) has sent the first IdentificationDeclaration message, via * verifyOrEstablishConnection(), to the Commissioner containing CommissionerPasscode set to * true. @@ -130,27 +130,30 @@ MatterError verifyOrEstablishConnection( * PasscodeDialogDisplayed and CommissionerPasscode set to true. *

4. Client has handled the Commissioner's CommissionerDecelration message. *

5. Client prompted user to input Passcode from Commissioner. - *

6. Client has updated the commissioning session's PAKE verifier using the user input - * passcode. The client updated the CastingApp's AppParameters - * DataProvider and the AndroidChipPlatform's CommissionableData. This is - * done via the following: a. DataProvider.updateCommissionableDataSetupPasscode(long - * setupPasscode, int discriminator) b. - * CastingApp.getInstance().updateAndroidChipPlatformWithCommissionableData() + *

6. Client has updated the CastingApp's AppParameters DataProvider + * via the following function call: DataProvider.updateCommissionableDataSetupPasscode(long + * setupPasscode, int discriminator). This allows continueConnecting() to update the + * commissioning session's PAKE verifier with the user entered passcode. *

Note: The same connectionCallbacks and commissioningWindowTimeoutSec parameters passed * into verifyOrEstablishConnection() will be used. - * @return MatterError - Matter.NO_ERROR if request submitted successfully, otherwise a + * @return MatterError - MatterError.NO_ERROR if request submitted successfully, otherwise a * MatterError object corresponding to the error. */ MatterError continueConnecting(); + MatterError continueConnectingNative(); + /** - * @brief This cancels the Commissioner-Generated passcode commissioning flow started via the - * verifyOrEstablishConnection() API above. It constructs and sends an - * IdentificationDeclaration message to the Commissioner containing CancelPasscode set to - * true. It is used to indicate that the Commissionee user has cancelled the commissioning - * process. This indicates that the Commissioner can dismiss any dialogs corresponding to - * commissioning, such as a Passcode input dialog or a Passcode display dialog. - * @return MatterError - Matter.NO_ERROR if request submitted successfully, otherwise a + * @brief This cancels the CastingPlayer/Commissioner-Generated passcode commissioning flow + * started via the VerifyOrEstablishConnection() API above. It constructs and sends an + * IdentificationDeclaration message to the CastingPlayer/Commissioner containing + * CancelPasscode set to true. It is used to indicate that the user, and thus the + * Client/Commissionee, have cancelled the commissioning process. This indicates that the + * CastingPlayer/Commissioner can dismiss any dialogs corresponding to commissioning, such as + * a Passcode input dialog or a Passcode display dialog. + *

Note: stopConnecting() does not call the onSuccess() callback passed to the + * VerifyOrEstablishConnection() API above since no connection is established. + * @return MatterError - MatterError.NO_ERROR if request submitted successfully, otherwise a * MatterError object corresponding to the error. */ MatterError stopConnecting(); diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/MatterCastingPlayer.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/MatterCastingPlayer.java index 523e8b01a56bee..4ccc9e1f914035 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/MatterCastingPlayer.java +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/MatterCastingPlayer.java @@ -25,7 +25,7 @@ import java.util.Objects; /** - * A Matter Casting Player represents a Matter commissioner that is able to play media to a physical + * A Matter Casting Player represents a Matter Commissioner that is able to play media to a physical * output or to a display screen which is part of the device (e.g. TV). It is discovered on the * local network using Matter Commissioner discovery over DNS. It contains all the information about * the service discovered/resolved. @@ -180,9 +180,9 @@ public boolean equals(Object o) { * a CommissionerDeclaration message from the Commissioner. This callback is needed to support * UDC features where a reply from the Commissioner is expected. It provides information * indicating the Commissioner’s pre-commissioning state. - *

For example: During Commissioner-Generated passcode commissioning, the Commissioner - * replies with a CommissionerDeclaration message with PasscodeDialogDisplayed and - * CommissionerPasscode set to true. Given these Commissioner state details, the client is + *

For example: During CastingPlayer/Commissioner-Generated passcode commissioning, the + * Commissioner replies with a CommissionerDeclaration message with PasscodeDialogDisplayed + * and CommissionerPasscode set to true. Given these Commissioner state details, the client is * expected to perform some actions, detailed in the continueConnecting() API below, and then * call the continueConnecting() API to complete the process. * @param commissioningWindowTimeoutSec (Optional) time (in sec) to keep the commissioning window @@ -190,15 +190,15 @@ public boolean equals(Object o) { * @param idOptions (Optional) Parameters in the IdentificationDeclaration message sent by the * Commissionee to the Commissioner. These parameters specify the information relating to the * requested commissioning session. - *

For example: To invoke the Commissioner-Generated passcode commissioning flow, the - * client would call this API with IdentificationDeclarationOptions containing + *

For example: To invoke the CastingPlayer/Commissioner-Generated passcode commissioning + * flow, the client would call this API with IdentificationDeclarationOptions containing * CommissionerPasscode set to true. See IdentificationDeclarationOptions.java for a complete * list of optional parameters. *

Furthermore, attributes (such as VendorId) describe the TargetApp that the client wants * to interact with after commissioning. If this value is passed in, * verifyOrEstablishConnection() will force UDC, in case the desired TargetApp is not found in * the on-device CastingStore. - * @return MatterError - Matter.NO_ERROR if request submitted successfully, otherwise a + * @return MatterError - MatterError.NO_ERROR if request submitted successfully, otherwise a * MatterError object corresponding to the error. */ @Override @@ -212,7 +212,7 @@ public native MatterError verifyOrEstablishConnection( * * @param connectionCallbacks contains the onSuccess (Required), onFailure (Required) and * onCommissionerDeclaration (Optional) callbacks defiend in ConnectCallbacks.java. - * @return MatterError - Matter.NO_ERROR if request submitted successfully, otherwise a + * @return MatterError - MatterError.NO_ERROR if request submitted successfully, otherwise a * MatterError object corresponding to the error. */ @Override @@ -222,11 +222,11 @@ public MatterError verifyOrEstablishConnection(ConnectionCallbacks connectionCal } /** - * @brief This is a continuation of the Commissioner-Generated passcode commissioning flow started - * via the verifyOrEstablishConnection() API above. It continues the UDC process by sending a - * second IdentificationDeclaration message to Commissioner containing CommissionerPasscode - * and CommissionerPasscodeReady set to true. At this point it is assumed that the following - * have occurred: + * @brief This is a continuation of the CastingPlayer/Commissioner-Generated passcode + * commissioning flow started via the verifyOrEstablishConnection() API above. It continues + * the UDC process by sending a second IdentificationDeclaration message to Commissioner + * containing CommissionerPasscode and CommissionerPasscodeReady set to true. At this point it + * is assumed that the following have occurred: *

1. Client (Commissionee) has sent the first IdentificationDeclaration message, via * verifyOrEstablishConnection(), to the Commissioner containing CommissionerPasscode set to * true. @@ -235,27 +235,40 @@ public MatterError verifyOrEstablishConnection(ConnectionCallbacks connectionCal * PasscodeDialogDisplayed and CommissionerPasscode set to true. *

4. Client has handled the Commissioner's CommissionerDecelration message. *

5. Client prompted user to input Passcode from Commissioner. - *

6. Client has updated the commissioning session's PAKE verifier using the user input - * passcode. The client updated the CastingApp's AppParameters - * DataProvider and the AndroidChipPlatform's CommissionableData. This is - * done via the following: a. DataProvider.updateCommissionableDataSetupPasscode(long - * setupPasscode, int discriminator) b. - * CastingApp.getInstance().updateAndroidChipPlatformWithCommissionableData() + *

6. Client has updated the CastingApp's AppParameters DataProvider + * via the following function call: DataProvider.updateCommissionableDataSetupPasscode(long + * setupPasscode, int discriminator). This allows continueConnecting() to update the + * commissioning session's PAKE verifier with the user entered passcode. *

Note: The same connectionCallbacks and commissioningWindowTimeoutSec parameters passed * into verifyOrEstablishConnection() will be used. - * @return MatterError - Matter.NO_ERROR if request submitted successfully, otherwise a + * @return MatterError - MatterError.NO_ERROR if request submitted successfully, otherwise a * MatterError object corresponding to the error. */ - public native MatterError continueConnecting(); + public MatterError continueConnecting() { + Log.d(TAG, "continueConnecting()"); + // Update AndroidChipPlatform's CommissionableData with the user entered passcode. + MatterError err = CastingApp.getInstance().updateAndroidChipPlatformWithCommissionableData(); + if (err != MatterError.NO_ERROR) { + Log.e(TAG, "continueConnecting() Error updating AndroidChipPlatform with CommissionableData"); + return err; + } + Log.d(TAG, "continueConnecting() calling continueConnectingNative()"); + return continueConnectingNative(); + } + + public native MatterError continueConnectingNative(); /** - * @brief This cancels the Commissioner-Generated passcode commissioning flow started via the - * verifyOrEstablishConnection() API above. It constructs and sends an - * IdentificationDeclaration message to the Commissioner containing CancelPasscode set to - * true. It is used to indicate that the Commissionee user has cancelled the commissioning - * process. This indicates that the Commissioner can dismiss any dialogs corresponding to - * commissioning, such as a Passcode input dialog or a Passcode display dialog. - * @return MatterError - Matter.NO_ERROR if request submitted successfully, otherwise a + * @brief This cancels the CastingPlayer/Commissioner-Generated passcode commissioning flow + * started via the VerifyOrEstablishConnection() API above. It constructs and sends an + * IdentificationDeclaration message to the CastingPlayer/Commissioner containing + * CancelPasscode set to true. It is used to indicate that the user, and thus the + * Client/Commissionee, have cancelled the commissioning process. This indicates that the + * CastingPlayer/Commissioner can dismiss any dialogs corresponding to commissioning, such as + * a Passcode input dialog or a Passcode display dialog. + *

Note: stopConnecting() does not call the onSuccess() callback passed to the + * VerifyOrEstablishConnection() API above since no connection is established. + * @return MatterError - MatterError.NO_ERROR if request submitted successfully, otherwise a * MatterError object corresponding to the error. */ public native MatterError stopConnecting(); diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/AppParameters.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/AppParameters.java index 6b25d7b6aa1981..0734271ca89b88 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/AppParameters.java +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/AppParameters.java @@ -28,8 +28,7 @@ public class AppParameters { @NonNull private final DataProvider rotatingDeviceIdUniqueIdProvider; - // Not final since it needs to be updated during Commissioner-Generated passcode commissioning. - @NonNull private DataProvider commissionableDataProvider; + @NonNull private final DataProvider commissionableDataProvider; @NonNull private final DACProvider dacProvider; diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/CommissionerDeclaration.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/CommissionerDeclaration.java index 098d3041141536..82213a3a69517d 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/CommissionerDeclaration.java +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/CommissionerDeclaration.java @@ -17,11 +17,12 @@ /** * Represents the Commissioner Declaration message sent by a User Directed Commissioning server - * (Casting Player) to a UDC client (tv-casting-app). + * (CastingPlayer/Commissioner) to a UDC client (Casting Client/Commissionee). */ public class CommissionerDeclaration { static final String TAG = CommissionerDeclaration.class.getSimpleName(); + /** The allowed values for the ErrorCode field are the following */ public enum CdError { kNoError(0), kCommissionableDiscoveryFailed(1), @@ -52,13 +53,34 @@ public int getValue() { return value; } } - - private CdError mErrorCode = CdError.kNoError; - private boolean mNeedsPasscode = false; - private boolean mNoAppsFound = false; - private boolean mPasscodeDialogDisplayed = false; - private boolean mCommissionerPasscode = false; - private boolean mQRCodeDisplayed = false; + /** Feature: All - Indicates errors incurred during commissioning. */ + private CdError errorCode = CdError.kNoError; + /** + * Feature: Coordinate PIN Dialogs - When NoPasscode field set to true, and the Commissioner + * determines that a Passcode code will be needed for commissioning. + */ + private boolean needsPasscode = false; + /** + * Feature: Target Content Application - No apps with AccountLogin cluster implementation were + * found for the last IdentificationDeclaration request. Only apps which provide access to the + * vendor id of the Commissionee will be considered. + */ + private boolean noAppsFound = false; + /** + * Feature: Coordinate PIN Dialogs - A Passcode input dialog is now displayed for the user on the + * Commissioner. + */ + private boolean passcodeDialogDisplayed = false; + /** + * Feature: Commissioner-Generated Passcode - A Passcode is now displayed for the user by the + * CastingPlayer/Commissioner. + */ + private boolean commissionerPasscode = false; + /** + * Feature: Commissioner-Generated Passcode - The user experience conveying a Passcode to the user + * also displays a QR code. + */ + private boolean qRCodeDisplayed = false; public CommissionerDeclaration( int errorCode, @@ -66,70 +88,85 @@ public CommissionerDeclaration( boolean noAppsFound, boolean passcodeDialogDisplayed, boolean commissionerPasscode, - boolean qrCodeDisplayed) { - mErrorCode = CdError.values()[errorCode]; - mNeedsPasscode = needsPasscode; - mNoAppsFound = noAppsFound; - mPasscodeDialogDisplayed = passcodeDialogDisplayed; - mCommissionerPasscode = commissionerPasscode; - mQRCodeDisplayed = qrCodeDisplayed; + boolean qRCodeDisplayed) { + this.errorCode = CdError.values()[errorCode]; + this.needsPasscode = needsPasscode; + this.noAppsFound = noAppsFound; + this.passcodeDialogDisplayed = passcodeDialogDisplayed; + this.commissionerPasscode = commissionerPasscode; + this.qRCodeDisplayed = qRCodeDisplayed; } - public void setErrorCode(CdError newValue) { - mErrorCode = newValue; + public void setErrorCode(CdError errorCode) { + this.errorCode = errorCode; } public CdError getErrorCode() { - return mErrorCode; + return this.errorCode; } - public void setNeedsPasscode(boolean newValue) { - mNeedsPasscode = newValue; + public void setNeedsPasscode(boolean needsPasscode) { + this.needsPasscode = needsPasscode; } public boolean getNeedsPasscode() { - return mNeedsPasscode; + return this.needsPasscode; } - public void setNoAppsFound(boolean newValue) { - mNoAppsFound = newValue; + public void setNoAppsFound(boolean noAppsFound) { + this.noAppsFound = noAppsFound; } public boolean getNoAppsFound() { - return mNoAppsFound; + return this.noAppsFound; } - public void setPasscodeDialogDisplayed(boolean newValue) { - mPasscodeDialogDisplayed = newValue; + public void setPasscodeDialogDisplayed(boolean passcodeDialogDisplayed) { + this.passcodeDialogDisplayed = passcodeDialogDisplayed; } public boolean getPasscodeDialogDisplayed() { - return mPasscodeDialogDisplayed; + return this.passcodeDialogDisplayed; } - public void setCommissionerPasscode(boolean newValue) { - mCommissionerPasscode = newValue; + public void setCommissionerPasscode(boolean commissionerPasscode) { + this.commissionerPasscode = commissionerPasscode; } public boolean getCommissionerPasscode() { - return mCommissionerPasscode; + return this.commissionerPasscode; } - public void setQRCodeDisplayed(boolean newValue) { - mQRCodeDisplayed = newValue; + public void setQRCodeDisplayed(boolean qRCodeDisplayed) { + this.qRCodeDisplayed = qRCodeDisplayed; } public boolean getQRCodeDisplayed() { - return mQRCodeDisplayed; + return this.qRCodeDisplayed; + } + + @Override + public String toString() { + return "CommissionerDeclaration::errorCode: " + + errorCode.name() + + "\n" + + "CommissionerDeclaration::needsPasscode: " + + needsPasscode + + "\n" + + "CommissionerDeclaration::noAppsFound: " + + noAppsFound + + "\n" + + "CommissionerDeclaration::passcodeDialogDisplayed: " + + passcodeDialogDisplayed + + "\n" + + "CommissionerDeclaration:commissionerPasscode: " + + commissionerPasscode + + "\n" + + "CommissionerDeclaration::qRCodeDisplayed: " + + qRCodeDisplayed; } public void logDetail() { - Log.d(TAG, "CommissionerDeclaration::logDetail() - java"); - Log.d(TAG, "CommissionerDeclaration::mErrorCode: " + mErrorCode.name()); - Log.d(TAG, "CommissionerDeclaration::mNeedsPasscode: " + mNeedsPasscode); - Log.d(TAG, "CommissionerDeclaration::mNoAppsFound: " + mNoAppsFound); - Log.d(TAG, "CommissionerDeclaration::mPasscodeDialogDisplayed: " + mPasscodeDialogDisplayed); - Log.d(TAG, "CommissionerDeclaration::mCommissionerPasscode: " + mCommissionerPasscode); - Log.d(TAG, "CommissionerDeclaration::mQRCodeDisplayed: " + mQRCodeDisplayed); + Log.d(TAG, "CommissionerDeclaration::logDetail()\n" + this.toString()); } } diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/DataProvider.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/DataProvider.java index 773358a39f9b6a..854cf76ce8aca8 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/DataProvider.java +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/DataProvider.java @@ -27,21 +27,10 @@ default T _get() { try { val = get(); } catch (Throwable t) { - Log.e(TAG, "DataProvider::Caught an unhandled Throwable from the client: " + t); + Log.e(TAG, "DataProvider::_get() Caught an unhandled Throwable from the client: " + t); } return val; } public abstract T get(); - - /** - * Must be implemented in the CommissionableData DataProvider if the Commissioner-Generated - * passcode commissioning flow is going to be used. In this flow, the setup passcode is generated - * by the CastingPlayer and entered by the user in the tv-casting-app CX. Once it is obtained, - * this function should be called with the Commissioner-Generated passcode to update the - * CommissionableData DataProvider in AppParameters. The client is also responsible for calling - * CastingApp::updateAndroidChipPlatformWithCommissionableData() to update the data provider set - * which was previously set in the AppParameters and AndroidChipPlatform at initialization time. - */ - default void updateCommissionableDataSetupPasscode(long setupPasscode, int discriminator) {} } diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/IdentificationDeclarationOptions.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/IdentificationDeclarationOptions.java index 352400238e854c..df87171e92bca9 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/IdentificationDeclarationOptions.java +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/IdentificationDeclarationOptions.java @@ -28,81 +28,105 @@ public class IdentificationDeclarationOptions { public IdentificationDeclarationOptions() {} + public IdentificationDeclarationOptions( + boolean noPasscode, + boolean cdUponPasscodeDialog, + boolean commissionerPasscode, + boolean commissionerPasscodeReady, + boolean cancelPasscode, + List targetAppInfos) { + this.noPasscode = noPasscode; + this.cdUponPasscodeDialog = cdUponPasscodeDialog; + this.commissionerPasscode = commissionerPasscode; + this.commissionerPasscodeReady = commissionerPasscodeReady; + this.cancelPasscode = cancelPasscode; + this.targetAppInfos = targetAppInfos != null ? targetAppInfos : new ArrayList<>(); + } + /** - * Feature: Target Content Application Flag to instruct the Commissioner not to display a Passcode - * input dialog, and instead send a CommissionerDeclaration message if a commissioning Passcode is - * needed. + * Feature: Target Content Application - Flag to instruct the Commissioner not to display a + * Passcode input dialog, and instead send a CommissionerDeclaration message if a commissioning + * Passcode is needed. */ - public boolean mNoPasscode = false; + public boolean noPasscode = false; /** - * Feature: Coordinate Passcode Dialogs Flag to instruct the Commissioner to send a + * Feature: Coordinate Passcode Dialogs - Flag to instruct the Commissioner to send a * CommissionerDeclaration message when the Passcode input dialog on the Commissioner has been * shown to the user. */ - public boolean mCdUponPasscodeDialog = false; + public boolean cdUponPasscodeDialog = false; /** - * Feature: Commissioner-Generated Passcode Flag to instruct the Commissioner to use the + * Feature: Commissioner-Generated Passcode - Flag to instruct the Commissioner to use the * Commissioner-generated Passcode for commissioning. */ - public boolean mCommissionerPasscode = false; + public boolean commissionerPasscode = false; /** - * Feature: Commissioner-Generated Passcode Flag to indicate whether or not the Commissionee has + * Feature: Commissioner-Generated Passcode - Flag to indicate whether or not the Commissionee has * obtained the Commissioner Passcode from the user and is therefore ready for commissioning. */ - public boolean mCommissionerPasscodeReady = false; + public boolean commissionerPasscodeReady = false; /** - * Feature: Coordinate Passcode Dialogs Flag to indicate when the Commissionee user has decided to - * exit the commissioning process. + * Feature: Coordinate Passcode Dialogs Flag - to indicate when the Commissionee user has decided + * to exit the commissioning process. */ - public boolean mCancelPasscode = false; + public boolean cancelPasscode = false; /** - * Feature: Target Content Application The set of content app Vendor IDs (and optionally, Product - * IDs) that can be used for authentication. Also, if TargetAppInfo is passed in, + * Feature: Target Content Application - The set of content app Vendor IDs (and optionally, + * Product IDs) that can be used for authentication. Also, if TargetAppInfo is passed in, * VerifyOrEstablishConnection() will force User Directed Commissioning, in case the desired * TargetApp is not found in the on-device CastingStore. */ - private List mTargetAppInfos = new ArrayList<>(); + private List targetAppInfos = new ArrayList<>(); public boolean addTargetAppInfo(TargetAppInfo targetAppInfo) { Log.d(TAG, "addTargetAppInfo()"); - if (mTargetAppInfos.size() >= CHIP_DEVICE_CONFIG_UDC_MAX_TARGET_APPS) { + if (targetAppInfos.size() >= CHIP_DEVICE_CONFIG_UDC_MAX_TARGET_APPS) { Log.e( TAG, "addTargetAppInfo() failed to add TargetAppInfo, max list size is {0}" + CHIP_DEVICE_CONFIG_UDC_MAX_TARGET_APPS); return false; } - mTargetAppInfos.add(targetAppInfo); + targetAppInfos.add(targetAppInfo); return true; } public List getTargetAppInfoList() { - return mTargetAppInfos; + return targetAppInfos; } - public void logDetail() { - Log.d(TAG, "IdentificationDeclarationOptions::logDetail() - java"); - Log.d(TAG, "IdentificationDeclarationOptions::mNoPasscode: " + mNoPasscode); - Log.d( - TAG, - "IdentificationDeclarationOptions::mCdUponPasscodeDialog: " + mCdUponPasscodeDialog); - Log.d( - TAG, - "IdentificationDeclarationOptions::mCommissionerPasscode: " + mCommissionerPasscode); - Log.d( - TAG, - "IdentificationDeclarationOptions::mCommissionerPasscodeReady: " - + mCommissionerPasscodeReady); - Log.d(TAG, "IdentificationDeclarationOptions::mCancelPasscode: " + mCancelPasscode); - Log.d(TAG, "IdentificationDeclarationOptions::mTargetAppInfos list: "); + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("IdentificationDeclarationOptions::noPasscode: ") + .append(noPasscode) + .append("\n"); + sb.append("IdentificationDeclarationOptions::cdUponPasscodeDialog: ") + .append(cdUponPasscodeDialog) + .append("\n"); + sb.append("IdentificationDeclarationOptions::commissionerPasscode: ") + .append(commissionerPasscode) + .append("\n"); + sb.append("IdentificationDeclarationOptions::commissionerPasscodeReady: ") + .append(commissionerPasscodeReady) + .append("\n"); + sb.append("IdentificationDeclarationOptions::cancelPasscode: ") + .append(cancelPasscode) + .append("\n"); + sb.append("IdentificationDeclarationOptions::targetAppInfos list: \n"); - for (TargetAppInfo targetAppInfo : mTargetAppInfos) { - Log.d( - TAG, - "\t\tTargetAppInfo - Vendor ID: " - + targetAppInfo.vendorId - + ", Product ID: " - + targetAppInfo.productId); + for (TargetAppInfo targetAppInfo : targetAppInfos) { + sb.append("\t\tTargetAppInfo - Vendor ID: ") + .append(targetAppInfo.vendorId) + .append(", Product ID: ") + .append(targetAppInfo.productId) + .append("\n"); } + + return sb.toString(); + } + + public void logDetail() { + Log.d(TAG, "IdentificationDeclarationOptions::logDetail()\n" + this.toString()); } } diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.cpp index a2b0565f30946d..4bb7022b7a0d50 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.cpp +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.cpp @@ -106,7 +106,6 @@ JNI_METHOD(jobject, verifyOrEstablishConnection) MatterCastingPlayerJNIMgr().mConnectionSuccessHandler.SetUp(env, jSuccessCallback); MatterCastingPlayerJNIMgr().mConnectionFailureHandler.SetUp(env, jFailureCallback); - // auto connectCallback = [](CHIP_ERROR err, CastingPlayer * playerPtr) { ChipLogProgress(AppServer, "MatterCastingPlayer-JNI::verifyOrEstablishConnection() ConnectCallback()"); if (err == CHIP_NO_ERROR) @@ -175,7 +174,7 @@ JNI_METHOD(jobject, verifyOrEstablishConnection) return support::convertMatterErrorFromCppToJava(CHIP_NO_ERROR); } -JNI_METHOD(jobject, continueConnecting) +JNI_METHOD(jobject, continueConnectingNative) (JNIEnv * env, jobject thiz) { chip::DeviceLayer::StackLock lock; @@ -184,9 +183,7 @@ JNI_METHOD(jobject, continueConnecting) CastingPlayer * castingPlayer = support::convertCastingPlayerFromJavaToCpp(thiz); VerifyOrReturnValue(castingPlayer != nullptr, support::convertMatterErrorFromCppToJava(CHIP_ERROR_INVALID_ARGUMENT)); - castingPlayer->ContinueConnecting(); - - return support::convertMatterErrorFromCppToJava(CHIP_NO_ERROR); + return support::convertMatterErrorFromCppToJava(castingPlayer->ContinueConnecting()); } JNI_METHOD(jobject, stopConnecting) @@ -198,9 +195,7 @@ JNI_METHOD(jobject, stopConnecting) CastingPlayer * castingPlayer = support::convertCastingPlayerFromJavaToCpp(thiz); VerifyOrReturnValue(castingPlayer != nullptr, support::convertMatterErrorFromCppToJava(CHIP_ERROR_INVALID_ARGUMENT)); - castingPlayer->StopConnecting(); - - return support::convertMatterErrorFromCppToJava(CHIP_NO_ERROR); + return support::convertMatterErrorFromCppToJava(castingPlayer->StopConnecting()); } JNI_METHOD(void, disconnect) diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.h index 559fcc6a926b61..3e022b48f549fe 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.h +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.h @@ -27,13 +27,21 @@ namespace matter { namespace casting { namespace core { +/** + * This class is used to manage the JNI callbacks and C++ to Java conversions for the CastingPlayer. + */ class MatterCastingPlayerJNI { public: - MatterCastingPlayerJNI() : mConnectionSuccessHandler([](void *) { return nullptr; }) {} + // Member initializer list + MatterCastingPlayerJNI() : + mConnectionSuccessHandler([](void *) { return nullptr; }), + mConnectionFailureHandler(matter::casting::support::convertMatterErrorFromCppToJava), + mCommissionerDeclarationHandler(matter::casting::support::convertCommissionerDeclarationFromCppToJava) + {} support::MatterCallbackJNI mConnectionSuccessHandler; - support::MatterFailureCallbackJNI mConnectionFailureHandler; - support::MatterCommissionerDeclarationCallbackJNI mCommissionerDeclarationHandler; + support::MatterCallbackJNI mConnectionFailureHandler; + support::MatterCallbackJNI mCommissionerDeclarationHandler; private: friend MatterCastingPlayerJNI & MatterCastingPlayerJNIMgr(); diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/Converters-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/Converters-JNI.cpp index a3a4e9eb05d76a..c066a4a33c2f9a 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/Converters-JNI.cpp +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/Converters-JNI.cpp @@ -410,12 +410,12 @@ matter::casting::core::IdentificationDeclarationOptions * convertIdentificationD ChipLogError(AppServer, "convertIdentificationDeclarationOptionsFromJavaToCpp() IdentificationDeclarationOptions class not found!")); - jfieldID noPasscodeField = env->GetFieldID(idOptionsClass, "mNoPasscode", "Z"); - jfieldID cdUponPasscodeDialogField = env->GetFieldID(idOptionsClass, "mCdUponPasscodeDialog", "Z"); - jfieldID commissionerPasscodeField = env->GetFieldID(idOptionsClass, "mCommissionerPasscode", "Z"); - jfieldID commissionerPasscodeReadyField = env->GetFieldID(idOptionsClass, "mCommissionerPasscodeReady", "Z"); - jfieldID cancelPasscodeField = env->GetFieldID(idOptionsClass, "mCancelPasscode", "Z"); - jfieldID targetAppInfosField = env->GetFieldID(idOptionsClass, "mTargetAppInfos", "Ljava/util/List;"); + jfieldID noPasscodeField = env->GetFieldID(idOptionsClass, "noPasscode", "Z"); + jfieldID cdUponPasscodeDialogField = env->GetFieldID(idOptionsClass, "cdUponPasscodeDialog", "Z"); + jfieldID commissionerPasscodeField = env->GetFieldID(idOptionsClass, "commissionerPasscode", "Z"); + jfieldID commissionerPasscodeReadyField = env->GetFieldID(idOptionsClass, "commissionerPasscodeReady", "Z"); + jfieldID cancelPasscodeField = env->GetFieldID(idOptionsClass, "cancelPasscode", "Z"); + jfieldID targetAppInfosField = env->GetFieldID(idOptionsClass, "targetAppInfos", "Ljava/util/List;"); VerifyOrReturnValue( noPasscodeField != nullptr, nullptr, ChipLogError(AppServer, "convertIdentificationDeclarationOptionsFromJavaToCpp() noPasscodeField not found!")); diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/MatterCallback-JNI.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/MatterCallback-JNI.h index d67c9229c8d377..6bd185952535e7 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/MatterCallback-JNI.h +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/MatterCallback-JNI.h @@ -93,15 +93,6 @@ class MatterFailureCallbackJNI : public MatterCallbackJNI MatterFailureCallbackJNI() : MatterCallbackJNI(matter::casting::support::convertMatterErrorFromCppToJava) {} }; -class MatterCommissionerDeclarationCallbackJNI - : public MatterCallbackJNI -{ -public: - MatterCommissionerDeclarationCallbackJNI() : - MatterCallbackJNI(matter::casting::support::convertCommissionerDeclarationFromCppToJava) - {} -}; - }; // namespace support }; // namespace casting }; // namespace matter diff --git a/examples/tv-casting-app/android/App/app/src/main/res/layout/custom_passcode_dialog.xml b/examples/tv-casting-app/android/App/app/src/main/res/layout/custom_passcode_dialog.xml index 8c7d2ff04d7e25..1b868e06b71f29 100644 --- a/examples/tv-casting-app/android/App/app/src/main/res/layout/custom_passcode_dialog.xml +++ b/examples/tv-casting-app/android/App/app/src/main/res/layout/custom_passcode_dialog.xml @@ -13,7 +13,7 @@ android:padding="16dp" android:textColor="@android:color/white" android:gravity="center" - android:text="Title" /> + android:text="@string/matter_connection_input_dialog_title" /> + android:text="@string/matter_connection_input_dialog_instructions" /> Initializing Discovering Casting Players on-network: Discovery Stopped - Long click on a Casting Player to try the Commissioner-Generated passcode commissioning flow if supported. + Long click on a Casting Player to connect using CastingPlayer/Commissioner-Generated passcode commissioning flow (if supported). Start discovery error. - Start discovery error. Discovery ongoing, stop before starting. - Stop discovery error. - Next + Enter the Commissioner-Generated Passcode + Input the Commissioner-Generated passcode displayed on the CastingPlayer UX, or use the default provided (12345678). Select an action Content Launcher Launch URL Disconnect from Casting Player diff --git a/examples/tv-casting-app/linux/simple-app-helper.cpp b/examples/tv-casting-app/linux/simple-app-helper.cpp index 4432b11c850174..c961bd5adaaacb 100644 --- a/examples/tv-casting-app/linux/simple-app-helper.cpp +++ b/examples/tv-casting-app/linux/simple-app-helper.cpp @@ -486,7 +486,12 @@ CHIP_ERROR CommandHandler(int argc, char ** argv) } // Continue Connecting to the target CastingPlayer with the user entered Commissioner-generated Passcode. - targetCastingPlayer->ContinueConnecting(); + err = targetCastingPlayer->ContinueConnecting(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "CommandHandler() setcommissionerpasscode ContinueConnecting() err %" CHIP_ERROR_FORMAT, + err.Format()); + } } else { @@ -498,7 +503,11 @@ CHIP_ERROR CommandHandler(int argc, char ** argv) if (strcmp(argv[0], "stop-connecting") == 0) { ChipLogProgress(AppServer, "CommandHandler() stop-connecting"); - targetCastingPlayer->StopConnecting(); + CHIP_ERROR err = targetCastingPlayer->StopConnecting(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "CommandHandler() stop-connecting, err %" CHIP_ERROR_FORMAT, err.Format()); + } } if (strcmp(argv[0], "print-bindings") == 0) { diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp index 15b7e0598450df..22dd5e9f2b39a6 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp +++ b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp @@ -159,9 +159,9 @@ void CastingPlayer::VerifyOrEstablishConnection(ConnectionCallbacks connectionCa } else { - // We need to call OpenBasicCommissioningWindow() for both Commissionee-Generated passcode commissioning flow and - // Commissioner-Generated passcode commissioning flow. Per the Matter spec (UserDirectedCommissioning), even if the - // Commissionee sends an IdentificationDeclaration with CommissionerPasscode set to true, the Commissioner will first + // We need to call OpenBasicCommissioningWindow() for both the Client/Commissionee-Generated passcode commissioning flow and + // Casting Player/Commissioner-Generated passcode commissioning flow. Per the Matter spec (UserDirectedCommissioning), even + // if the Commissionee sends an IdentificationDeclaration with CommissionerPasscode set to true, the Commissioner will first // attempt to use AccountLogin in order to obtain Passcode using rotatingID. If no Passcode is obtained, Commissioner // displays a Passcode. ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection() calling OpenBasicCommissioningWindow()"); @@ -182,18 +182,20 @@ void CastingPlayer::VerifyOrEstablishConnection(ConnectionCallbacks connectionCa } } -void CastingPlayer::ContinueConnecting() +CHIP_ERROR CastingPlayer::ContinueConnecting() { ChipLogProgress(AppServer, "CastingPlayer::ContinueConnecting()"); - CHIP_ERROR err = CHIP_NO_ERROR; - // Verify that mOnCompleted is not nullptr. - VerifyOrExit(mOnCompleted != nullptr, ChipLogError(AppServer, "CastingPlayer::ContinueConnecting() mOnCompleted == nullptr")); - if (!matter::casting::core::CommissionerDeclarationHandler::GetInstance()->HasCommissionerDeclarationCallback()) - { - ChipLogProgress(AppServer, - "CastingPlayer::ContinueConnecting() CommissionerDeclaration message callback has not been set."); - } - mConnectionState = CASTING_PLAYER_CONNECTING; + VerifyOrReturnValue(mOnCompleted != nullptr, CHIP_ERROR_INVALID_ARGUMENT, + ChipLogError(AppServer, "CastingPlayer::ContinueConnecting() mOnCompleted == nullptr");); + VerifyOrReturnValue(mConnectionState == CASTING_PLAYER_CONNECTING, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(AppServer, "CastingPlayer::ContinueConnecting() called while not in connecting state");); + VerifyOrReturnValue( + mIdOptions.mCommissionerPasscode, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(AppServer, + "CastingPlayer::ContinueConnecting() mIdOptions.mCommissionerPasscode == false, ContinueConnecting() should " + "only be called when the CastingPlayer/Commissioner-Generated passcode commissioning flow is in progress.");); + + CHIP_ERROR err = CHIP_NO_ERROR; mTargetCastingPlayer = this; ChipLogProgress(AppServer, "CastingPlayer::ContinueConnecting() calling OpenBasicCommissioningWindow()"); @@ -212,33 +214,46 @@ void CastingPlayer::ContinueConnecting() ChipLogError(AppServer, "CastingPlayer::ContinueConnecting() failed with %" CHIP_ERROR_FORMAT, err.Format()); resetState(err); } + + return err; } -void CastingPlayer::StopConnecting() +CHIP_ERROR CastingPlayer::StopConnecting() { ChipLogProgress(AppServer, "CastingPlayer::StopConnecting()"); + VerifyOrReturnValue(mConnectionState == CASTING_PLAYER_CONNECTING, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(AppServer, "CastingPlayer::StopConnecting() called while not in connecting state");); + VerifyOrReturnValue( + mIdOptions.mCommissionerPasscode, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(AppServer, + "CastingPlayer::StopConnecting() mIdOptions.mCommissionerPasscode == false, ContinueConnecting() should only " + "be called when the CastingPlayer/Commissioner-Generated passcode commissioning flow is in progress.");); + CHIP_ERROR err = CHIP_NO_ERROR; mIdOptions.resetState(); mIdOptions.mCancelPasscode = true; - - ChipLogProgress(AppServer, "CastingPlayer::StopConnecting() calling SendUserDirectedCommissioningRequest()"); + ChipLogProgress( + AppServer, + "CastingPlayer::StopConnecting() calling SendUserDirectedCommissioningRequest() to indicate user canceled passcode entry"); #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT SuccessOrExit(err = SendUserDirectedCommissioningRequest()); #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT + // SendUserDirectedCommissioningRequest() sets SetUdcStatus(true) when sending a UDC message. support::ChipDeviceEventHandler::SetUdcStatus(false); mConnectionState = CASTING_PLAYER_NOT_CONNECTED; mCommissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec; mTargetCastingPlayer = nullptr; - ChipLogProgress(AppServer, "CastingPlayer::StopConnecting() User Directed Commissioning stopped"); - exit: if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "CastingPlayer::StopConnecting() failed with %" CHIP_ERROR_FORMAT, err.Format()); resetState(err); } + + ChipLogProgress(AppServer, "CastingPlayer::StopConnecting() User Directed Commissioning stopped"); + return err; } void CastingPlayer::resetState(CHIP_ERROR err) diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h index 82978d6956b16b..517e210612ea8a 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h +++ b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h @@ -89,7 +89,7 @@ class ConnectionContext; class CastingPlayer; /** - * @brief CastingPlayer represents a Matter commissioner that is able to play media to a physical + * @brief CastingPlayer represents a Matter Commissioner that is able to play media to a physical * output or to a display screen which is part of the device. */ class CastingPlayer : public std::enable_shared_from_this @@ -133,19 +133,19 @@ class CastingPlayer : public std::enable_shared_from_this * where a Commissioner reply is expected, this API needs to be followed up with the ContinueConnecting() API defiend below. See * the Matter UDC specification or parameter class definitions for details on features not included in the description below. * - * @param connectionCallbacks contains the ConnectCallback (Required) and CommissionerDeclarationCallback (Optional) defiend in - * ConnectCallbacks.h. + * @param connectionCallbacks contains the ConnectCallback and CommissionerDeclarationCallback defiend in ConnectCallbacks.h. * - * ConnectCallback: The callback called when the connection process has ended, regardless of whether it was successful or not. + * ConnectCallback (Required): The callback called when the connection process has ended, regardless of whether it was + * successful or not. * - * CommissionerDeclarationCallback: The callback called when the Commissionee receives a CommissionerDeclaration message from - * the Commissioner. This callback is needed to support UDC features where a reply from the Commissioner is expected. It - * provides information indicating the Commissioner’s pre-commissioning state. + * CommissionerDeclarationCallback (Optional): The callback called when the Commissionee receives a CommissionerDeclaration + * message from the Commissioner. This callback is needed to support UDC features where a reply from the Commissioner is + * expected. It provides information indicating the Commissioner’s pre-commissioning state. * - * For example: During Commissioner-Generated passcode commissioning, the Commissioner replies with a CommissionerDeclaration - * message with PasscodeDialogDisplayed and CommissionerPasscode set to true. Given these Commissioner state details, the client - * is expected to perform some actions, detailed in the ContinueConnecting() API below, and then call the ContinueConnecting() - * API to complete the process. + * For example: During CastingPlayer/Commissioner-Generated passcode commissioning, the Commissioner replies with a + * CommissionerDeclaration message with PasscodeDialogDisplayed and CommissionerPasscode set to true. Given these Commissioner + * state details, the client is expected to perform some actions, detailed in the ContinueConnecting() API below, and then call + * the ContinueConnecting() API to complete the process. * * @param commissioningWindowTimeoutSec (Optional) time (in sec) to keep the commissioning window open, if commissioning is * required. Needs to be >= kCommissioningWindowTimeoutSec. @@ -153,9 +153,9 @@ class CastingPlayer : public std::enable_shared_from_this * @param idOptions (Optional) Parameters in the IdentificationDeclaration message sent by the Commissionee to the Commissioner. * These parameters specify the information relating to the requested commissioning session. * - * For example: To invoke the Commissioner-Generated passcode commissioning flow, the client would call this API with - * IdentificationDeclarationOptions containing CommissionerPasscode set to true. See IdentificationDeclarationOptions.h for a - * complete list of optional parameters. + * For example: To invoke the CastingPlayer/Commissioner-Generated passcode commissioning flow, the client would call this API + * with IdentificationDeclarationOptions containing CommissionerPasscode set to true. See IdentificationDeclarationOptions.h for + * a complete list of optional parameters. * * Furthermore, attributes (such as VendorId) describe the TargetApp that the client wants to interact with after commissioning. * If this value is passed in, VerifyOrEstablishConnection() will force UDC, in case the desired @@ -166,7 +166,7 @@ class CastingPlayer : public std::enable_shared_from_this IdentificationDeclarationOptions idOptions = IdentificationDeclarationOptions()); /** - * @brief This is a continuation of the Commissioner-Generated passcode commissioning flow started via the + * @brief This is a continuation of the CastingPlayer/Commissioner-Generated passcode commissioning flow started via the * VerifyOrEstablishConnection() API above. It continues the UDC process by sending a second IdentificationDeclaration message * to Commissioner containing CommissionerPasscode and CommissionerPasscodeReady set to true. At this point it is assumed that * the following have occurred: @@ -184,17 +184,21 @@ class CastingPlayer : public std::enable_shared_from_this * * The same connectionCallbacks and commissioningWindowTimeoutSec parameters passed into VerifyOrEstablishConnection() will be * used. + * @return CHIP_NO_ERROR if this function was called with the CastingPlayer in the correct state and an error otherwise. */ - void ContinueConnecting(); + CHIP_ERROR ContinueConnecting(); /** - * @brief This cancels the Commissioner-Generated passcode commissioning flow started via the VerifyOrEstablishConnection() API - * above. It constructs and sends an IdentificationDeclaration message to the Commissioner containing CancelPasscode set to - * true. It is used to indicate that the Commissionee user has cancelled the commissioning process. This indicates that the - * Commissioner can dismiss any dialogs corresponding to commissioning, such as a Passcode input dialog or a Passcode display - * dialog. + * @brief This cancels the CastingPlayer/Commissioner-Generated passcode commissioning flow started via the + * VerifyOrEstablishConnection() API above. It constructs and sends an IdentificationDeclaration message to the + * CastingPlayer/Commissioner containing CancelPasscode set to true. It is used to indicate that the user, and thus the + * Client/Commissionee, have cancelled the commissioning process. This indicates that the CastingPlayer/Commissioner can dismiss + * any dialogs corresponding to commissioning, such as a Passcode input dialog or a Passcode display dialog. + * Note: stopConnecting() does not call the ConnectCallback() callback passed to the VerifyOrEstablishConnection() API above + * since no connection is established. + * @return CHIP_NO_ERROR if this function was called with the CastingPlayer in the correct state and an error otherwise. */ - void StopConnecting(); + CHIP_ERROR StopConnecting(); /** * @brief Sets the internal connection state of this CastingPlayer to "disconnected"