blob: ff0d73133ef20a08af45bc065f61b7b9c2d7a108 [file] [log] [blame]
joonhaengHeo9bd79152022-06-14 23:23:38 +09001/*
2 * Copyright (c) 2022 Project CHIP Authors
3 * All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include "AndroidCommissioningWindowOpener.h"
19
20#include <app-common/zap-generated/cluster-objects.h>
joonhaengHeo9bd79152022-06-14 23:23:38 +090021#include <lib/core/CHIPSafeCasts.h>
22#include <lib/support/CHIPMem.h>
23#include <lib/support/JniReferences.h>
24#include <lib/support/JniTypeWrappers.h>
25#include <protocols/secure_channel/PASESession.h>
26#include <setup_payload/ManualSetupPayloadGenerator.h>
27#include <setup_payload/QRCodeSetupPayloadGenerator.h>
joonhaengHeo9bd79152022-06-14 23:23:38 +090028
Andrei Litvin660c9282024-04-04 18:34:51 -040029#include <string>
30
joonhaengHeo9bd79152022-06-14 23:23:38 +090031using namespace chip::app::Clusters;
32using namespace chip::System::Clock;
33
34namespace chip {
35namespace Controller {
36
37AndroidCommissioningWindowOpener::AndroidCommissioningWindowOpener(DeviceController * controller, jobject jCallbackObject) :
38 CommissioningWindowOpener(controller), mOnOpenCommissioningWindowCallback(OnOpenCommissioningWindowResponse, this),
39 mOnOpenBasicCommissioningWindowCallback(OnOpenBasicCommissioningWindowResponse, this)
40{
yunhanw-google91670ba2024-02-07 17:37:01 -080041 JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
42 if (mJavaCallback.Init(jCallbackObject) != CHIP_NO_ERROR)
yunhanw-googleccdbfee2023-10-05 16:48:27 -070043 {
44 ChipLogError(Controller, "Failed to create global reference for mJavaCallback");
45 return;
46 }
joonhaengHeo9bd79152022-06-14 23:23:38 +090047
48 jclass callbackClass = env->GetObjectClass(jCallbackObject);
49
50 mOnSuccessMethod = env->GetMethodID(callbackClass, "onSuccess", "(JLjava/lang/String;Ljava/lang/String;)V");
51 if (mOnSuccessMethod == nullptr)
52 {
53 ChipLogError(Controller, "Failed to access callback 'onSuccess' method");
54 env->ExceptionClear();
55 }
56
57 mOnErrorMethod = env->GetMethodID(callbackClass, "onError", "(IJ)V");
58 if (mOnErrorMethod == nullptr)
59 {
60 ChipLogError(Controller, "Failed to access callback 'onError' method");
61 env->ExceptionClear();
62 }
63}
64
joonhaengHeo9bd79152022-06-14 23:23:38 +090065CHIP_ERROR AndroidCommissioningWindowOpener::OpenBasicCommissioningWindow(DeviceController * controller, NodeId deviceId,
66 Seconds16 timeout, jobject jcallback)
67{
68 // Not using Platform::New because we want to keep our constructor private.
69 auto * opener = new AndroidCommissioningWindowOpener(controller, jcallback);
70 if (opener == nullptr)
71 {
72 return CHIP_ERROR_NO_MEMORY;
73 }
74
75 CHIP_ERROR err = opener->CommissioningWindowOpener::OpenBasicCommissioningWindow(
76 deviceId, timeout, &opener->mOnOpenBasicCommissioningWindowCallback);
77 if (err != CHIP_NO_ERROR)
78 {
79 delete opener;
80 }
81 // Else will clean up when the callback is called.
82 return err;
83}
84
85CHIP_ERROR AndroidCommissioningWindowOpener::OpenCommissioningWindow(DeviceController * controller, NodeId deviceId,
86 Seconds16 timeout, uint32_t iteration, uint16_t discriminator,
87 Optional<uint32_t> setupPIN, Optional<ByteSpan> salt,
88 jobject jcallback, SetupPayload & payload,
89 bool readVIDPIDAttributes)
90{
91 // Not using Platform::New because we want to keep our constructor private.
92 auto * opener = new AndroidCommissioningWindowOpener(controller, jcallback);
93 if (opener == nullptr)
94 {
95 return CHIP_ERROR_NO_MEMORY;
96 }
97
98 CHIP_ERROR err = opener->CommissioningWindowOpener::OpenCommissioningWindow(
99 deviceId, timeout, iteration, discriminator, setupPIN, salt, &opener->mOnOpenCommissioningWindowCallback, payload,
100 readVIDPIDAttributes);
101 if (err != CHIP_NO_ERROR)
102 {
103 delete opener;
104 }
105 // Else will clean up when the callback is called.
106 return err;
107}
108
109void AndroidCommissioningWindowOpener::OnOpenCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status,
110 chip::SetupPayload payload)
111{
112 auto * self = static_cast<AndroidCommissioningWindowOpener *>(context);
113 JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
yunhanw-googleccdbfee2023-10-05 16:48:27 -0700114 VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread"));
yunhanw-google20052322024-02-01 05:24:56 -0800115 JniLocalReferenceScope scope(env);
joonhaengHeo9bd79152022-06-14 23:23:38 +0900116
yunhanw-google91670ba2024-02-07 17:37:01 -0800117 VerifyOrExit(self->mJavaCallback.HasValidObjectRef(), ChipLogError(Controller, "mJavaCallback is not allocated."));
joonhaengHeo9bd79152022-06-14 23:23:38 +0900118
119 if (status == CHIP_NO_ERROR)
120 {
121 std::string QRCode;
122 std::string manualPairingCode;
123
Boris Zbarskyad5253a2023-05-26 02:22:37 -0400124 SuccessOrExit(status = ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(manualPairingCode));
125 SuccessOrExit(status = QRCodeSetupPayloadGenerator(payload).payloadBase38Representation(QRCode));
joonhaengHeo9bd79152022-06-14 23:23:38 +0900126
127 if (self->mOnSuccessMethod != nullptr)
128 {
129 UtfString jManualPairingCode(env, manualPairingCode.c_str());
130 UtfString jQRCode(env, QRCode.c_str());
yunhanw-google91670ba2024-02-07 17:37:01 -0800131 env->CallVoidMethod(self->mJavaCallback.ObjectRef(), self->mOnSuccessMethod, static_cast<jlong>(deviceId),
joonhaengHeo9bd79152022-06-14 23:23:38 +0900132 jManualPairingCode.jniValue(), jQRCode.jniValue());
133 }
134 }
135 else
136 {
137 if (self->mOnErrorMethod != nullptr)
138 {
yunhanw-google91670ba2024-02-07 17:37:01 -0800139 env->CallVoidMethod(self->mJavaCallback.ObjectRef(), self->mOnErrorMethod, static_cast<jint>(status.GetValue()),
joonhaengHeo9bd79152022-06-14 23:23:38 +0900140 static_cast<jlong>(deviceId));
141 }
142 }
143exit:
144 delete self;
145}
146
147void AndroidCommissioningWindowOpener::OnOpenBasicCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status)
148{
149 auto * self = static_cast<AndroidCommissioningWindowOpener *>(context);
yunhanw-google91670ba2024-02-07 17:37:01 -0800150 if (self->mJavaCallback.HasValidObjectRef())
joonhaengHeo9bd79152022-06-14 23:23:38 +0900151 {
152 JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
yunhanw-googleccdbfee2023-10-05 16:48:27 -0700153 VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread"));
yunhanw-google20052322024-02-01 05:24:56 -0800154 JniLocalReferenceScope scope(env);
joonhaengHeo9bd79152022-06-14 23:23:38 +0900155 if (status == CHIP_NO_ERROR)
156 {
157 if (self->mOnSuccessMethod != nullptr)
158 {
159 UtfString jManualPairingCode(env, "");
160 UtfString jQRCode(env, "");
yunhanw-google91670ba2024-02-07 17:37:01 -0800161 env->CallVoidMethod(self->mJavaCallback.ObjectRef(), self->mOnSuccessMethod, static_cast<jlong>(deviceId),
joonhaengHeo9bd79152022-06-14 23:23:38 +0900162 jManualPairingCode.jniValue(), jQRCode.jniValue());
163 }
164 }
165 else
166 {
167 if (self->mOnErrorMethod != nullptr)
168 {
yunhanw-google91670ba2024-02-07 17:37:01 -0800169 env->CallVoidMethod(self->mJavaCallback.ObjectRef(), self->mOnErrorMethod, static_cast<jint>(status.GetValue()),
joonhaengHeo9bd79152022-06-14 23:23:38 +0900170 static_cast<jlong>(deviceId));
171 }
172 }
173 }
174
175 delete self;
176}
177
178} // namespace Controller
179} // namespace chip