-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Android Open Commissioning Callback API (#19441)
* Add Android Open Commissioning Callback API * Restyled by google-java-format * Restyled by clang-format * Restyled by gn * Fix code below reviewer comment * Restyled by whitespace * Restyled by clang-format Co-authored-by: Restyled.io <[email protected]>
- Loading branch information
Showing
9 changed files
with
394 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
178 changes: 178 additions & 0 deletions
178
src/controller/java/AndroidCommissioningWindowOpener.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
/* | ||
* Copyright (c) 2022 Project CHIP Authors | ||
* All rights reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#include "AndroidCommissioningWindowOpener.h" | ||
|
||
#include <app-common/zap-generated/cluster-objects.h> | ||
#include <controller-clusters/zap-generated/CHIPClusters.h> | ||
#include <lib/core/CHIPSafeCasts.h> | ||
#include <lib/support/CHIPMem.h> | ||
#include <lib/support/JniReferences.h> | ||
#include <lib/support/JniTypeWrappers.h> | ||
#include <protocols/secure_channel/PASESession.h> | ||
#include <setup_payload/ManualSetupPayloadGenerator.h> | ||
#include <setup_payload/QRCodeSetupPayloadGenerator.h> | ||
|
||
using namespace chip::app::Clusters; | ||
using namespace chip::System::Clock; | ||
|
||
namespace chip { | ||
namespace Controller { | ||
|
||
AndroidCommissioningWindowOpener::AndroidCommissioningWindowOpener(DeviceController * controller, jobject jCallbackObject) : | ||
CommissioningWindowOpener(controller), mOnOpenCommissioningWindowCallback(OnOpenCommissioningWindowResponse, this), | ||
mOnOpenBasicCommissioningWindowCallback(OnOpenBasicCommissioningWindowResponse, this) | ||
{ | ||
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); | ||
mJavaCallback = env->NewGlobalRef(jCallbackObject); | ||
|
||
jclass callbackClass = env->GetObjectClass(jCallbackObject); | ||
|
||
mOnSuccessMethod = env->GetMethodID(callbackClass, "onSuccess", "(JLjava/lang/String;Ljava/lang/String;)V"); | ||
if (mOnSuccessMethod == nullptr) | ||
{ | ||
ChipLogError(Controller, "Failed to access callback 'onSuccess' method"); | ||
env->ExceptionClear(); | ||
} | ||
|
||
mOnErrorMethod = env->GetMethodID(callbackClass, "onError", "(IJ)V"); | ||
if (mOnErrorMethod == nullptr) | ||
{ | ||
ChipLogError(Controller, "Failed to access callback 'onError' method"); | ||
env->ExceptionClear(); | ||
} | ||
} | ||
|
||
AndroidCommissioningWindowOpener::~AndroidCommissioningWindowOpener() | ||
{ | ||
ChipLogError(Controller, "Delete AndroidCommissioningWindowOpener"); | ||
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); | ||
env->DeleteGlobalRef(mJavaCallback); | ||
} | ||
|
||
CHIP_ERROR AndroidCommissioningWindowOpener::OpenBasicCommissioningWindow(DeviceController * controller, NodeId deviceId, | ||
Seconds16 timeout, jobject jcallback) | ||
{ | ||
// Not using Platform::New because we want to keep our constructor private. | ||
auto * opener = new AndroidCommissioningWindowOpener(controller, jcallback); | ||
if (opener == nullptr) | ||
{ | ||
return CHIP_ERROR_NO_MEMORY; | ||
} | ||
|
||
CHIP_ERROR err = opener->CommissioningWindowOpener::OpenBasicCommissioningWindow( | ||
deviceId, timeout, &opener->mOnOpenBasicCommissioningWindowCallback); | ||
if (err != CHIP_NO_ERROR) | ||
{ | ||
delete opener; | ||
} | ||
// Else will clean up when the callback is called. | ||
return err; | ||
} | ||
|
||
CHIP_ERROR AndroidCommissioningWindowOpener::OpenCommissioningWindow(DeviceController * controller, NodeId deviceId, | ||
Seconds16 timeout, uint32_t iteration, uint16_t discriminator, | ||
Optional<uint32_t> setupPIN, Optional<ByteSpan> salt, | ||
jobject jcallback, SetupPayload & payload, | ||
bool readVIDPIDAttributes) | ||
{ | ||
// Not using Platform::New because we want to keep our constructor private. | ||
auto * opener = new AndroidCommissioningWindowOpener(controller, jcallback); | ||
if (opener == nullptr) | ||
{ | ||
return CHIP_ERROR_NO_MEMORY; | ||
} | ||
|
||
CHIP_ERROR err = opener->CommissioningWindowOpener::OpenCommissioningWindow( | ||
deviceId, timeout, iteration, discriminator, setupPIN, salt, &opener->mOnOpenCommissioningWindowCallback, payload, | ||
readVIDPIDAttributes); | ||
if (err != CHIP_NO_ERROR) | ||
{ | ||
delete opener; | ||
} | ||
// Else will clean up when the callback is called. | ||
return err; | ||
} | ||
|
||
void AndroidCommissioningWindowOpener::OnOpenCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status, | ||
chip::SetupPayload payload) | ||
{ | ||
auto * self = static_cast<AndroidCommissioningWindowOpener *>(context); | ||
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); | ||
|
||
VerifyOrExit(self->mJavaCallback != nullptr, ChipLogError(Controller, "mJavaCallback is not allocated.")); | ||
|
||
if (status == CHIP_NO_ERROR) | ||
{ | ||
std::string QRCode; | ||
std::string manualPairingCode; | ||
|
||
SuccessOrExit(ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(manualPairingCode)); | ||
SuccessOrExit(QRCodeSetupPayloadGenerator(payload).payloadBase38Representation(QRCode)); | ||
|
||
if (self->mOnSuccessMethod != nullptr) | ||
{ | ||
UtfString jManualPairingCode(env, manualPairingCode.c_str()); | ||
UtfString jQRCode(env, QRCode.c_str()); | ||
env->CallVoidMethod(self->mJavaCallback, self->mOnSuccessMethod, static_cast<jlong>(deviceId), | ||
jManualPairingCode.jniValue(), jQRCode.jniValue()); | ||
} | ||
} | ||
else | ||
{ | ||
if (self->mOnErrorMethod != nullptr) | ||
{ | ||
env->CallVoidMethod(self->mJavaCallback, self->mOnErrorMethod, static_cast<jint>(status.GetValue()), | ||
static_cast<jlong>(deviceId)); | ||
} | ||
} | ||
exit: | ||
delete self; | ||
} | ||
|
||
void AndroidCommissioningWindowOpener::OnOpenBasicCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status) | ||
{ | ||
auto * self = static_cast<AndroidCommissioningWindowOpener *>(context); | ||
|
||
if (self->mJavaCallback != nullptr) | ||
{ | ||
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); | ||
if (status == CHIP_NO_ERROR) | ||
{ | ||
if (self->mOnSuccessMethod != nullptr) | ||
{ | ||
UtfString jManualPairingCode(env, ""); | ||
UtfString jQRCode(env, ""); | ||
env->CallVoidMethod(self->mJavaCallback, self->mOnSuccessMethod, static_cast<jlong>(deviceId), | ||
jManualPairingCode.jniValue(), jQRCode.jniValue()); | ||
} | ||
} | ||
else | ||
{ | ||
if (self->mOnErrorMethod != nullptr) | ||
{ | ||
env->CallVoidMethod(self->mJavaCallback, self->mOnErrorMethod, static_cast<jint>(status.GetValue()), | ||
static_cast<jlong>(deviceId)); | ||
} | ||
} | ||
} | ||
|
||
delete self; | ||
} | ||
|
||
} // namespace Controller | ||
} // namespace chip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
* Copyright (c) 2022 Project CHIP Authors | ||
* All rights reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <controller/CommissioningWindowOpener.h> | ||
#include <jni.h> | ||
|
||
namespace chip { | ||
namespace Controller { | ||
|
||
/** | ||
* A helper class that can be used by consumers that don't care about the callback from the | ||
* open-commissioning-window process and just want automatic cleanup of the CommissioningWindowOpener when done | ||
* with it. | ||
*/ | ||
class AndroidCommissioningWindowOpener : private CommissioningWindowOpener | ||
{ | ||
public: | ||
// Takes the same arguments as CommissioningWindowOpener::OpenBasicCommissioningWindow except without the | ||
// callback. | ||
static CHIP_ERROR OpenBasicCommissioningWindow(DeviceController * controller, NodeId deviceId, System::Clock::Seconds16 timeout, | ||
jobject jcallback); | ||
// Takes the same arguments as CommissioningWindowOpener::OpenCommissioningWindow except without the | ||
// callback. | ||
static CHIP_ERROR OpenCommissioningWindow(DeviceController * controller, NodeId deviceId, System::Clock::Seconds16 timeout, | ||
uint32_t iteration, uint16_t discriminator, Optional<uint32_t> setupPIN, | ||
Optional<ByteSpan> salt, jobject jcallback, SetupPayload & payload, | ||
bool readVIDPIDAttributes = false); | ||
|
||
private: | ||
AndroidCommissioningWindowOpener(DeviceController * controller, jobject javaCallbackObject); | ||
~AndroidCommissioningWindowOpener(); | ||
|
||
static void OnOpenCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status, chip::SetupPayload payload); | ||
static void OnOpenBasicCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status); | ||
|
||
chip::Callback::Callback<chip::Controller::OnOpenCommissioningWindow> mOnOpenCommissioningWindowCallback; | ||
chip::Callback::Callback<chip::Controller::OnOpenBasicCommissioningWindow> mOnOpenBasicCommissioningWindowCallback; | ||
|
||
jobject mJavaCallback; | ||
jmethodID mOnSuccessMethod = nullptr; | ||
jmethodID mOnErrorMethod = nullptr; | ||
}; | ||
|
||
} // Namespace Controller | ||
} // namespace chip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.