| /* |
| * 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 <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> |
| |
| #include <string> |
| |
| 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(); |
| if (mJavaCallback.Init(jCallbackObject) != CHIP_NO_ERROR) |
| { |
| ChipLogError(Controller, "Failed to create global reference for mJavaCallback"); |
| return; |
| } |
| |
| 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(); |
| } |
| } |
| |
| 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(); |
| VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); |
| JniLocalReferenceScope scope(env); |
| |
| VerifyOrExit(self->mJavaCallback.HasValidObjectRef(), ChipLogError(Controller, "mJavaCallback is not allocated.")); |
| |
| if (status == CHIP_NO_ERROR) |
| { |
| std::string QRCode; |
| std::string manualPairingCode; |
| |
| SuccessOrExit(status = ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(manualPairingCode)); |
| SuccessOrExit(status = QRCodeSetupPayloadGenerator(payload).payloadBase38Representation(QRCode)); |
| |
| if (self->mOnSuccessMethod != nullptr) |
| { |
| UtfString jManualPairingCode(env, manualPairingCode.c_str()); |
| UtfString jQRCode(env, QRCode.c_str()); |
| env->CallVoidMethod(self->mJavaCallback.ObjectRef(), self->mOnSuccessMethod, static_cast<jlong>(deviceId), |
| jManualPairingCode.jniValue(), jQRCode.jniValue()); |
| } |
| } |
| else |
| { |
| if (self->mOnErrorMethod != nullptr) |
| { |
| env->CallVoidMethod(self->mJavaCallback.ObjectRef(), 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.HasValidObjectRef()) |
| { |
| JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); |
| VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); |
| JniLocalReferenceScope scope(env); |
| if (status == CHIP_NO_ERROR) |
| { |
| if (self->mOnSuccessMethod != nullptr) |
| { |
| UtfString jManualPairingCode(env, ""); |
| UtfString jQRCode(env, ""); |
| env->CallVoidMethod(self->mJavaCallback.ObjectRef(), self->mOnSuccessMethod, static_cast<jlong>(deviceId), |
| jManualPairingCode.jniValue(), jQRCode.jniValue()); |
| } |
| } |
| else |
| { |
| if (self->mOnErrorMethod != nullptr) |
| { |
| env->CallVoidMethod(self->mJavaCallback.ObjectRef(), self->mOnErrorMethod, static_cast<jint>(status.GetValue()), |
| static_cast<jlong>(deviceId)); |
| } |
| } |
| } |
| |
| delete self; |
| } |
| |
| } // namespace Controller |
| } // namespace chip |