2 * Copyright (c) 2020 Project CHIP Authors
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package com.google.chip.chiptool.provisioning
20 import android.os.Bundle
21 import android.util.Log
22 import android.view.LayoutInflater
23 import android.view.View
24 import android.view.ViewGroup
25 import android.widget.Toast
26 import androidx.fragment.app.Fragment
27 import com.google.chip.chiptool.ChipClient
28 import com.google.chip.chiptool.R
29 import kotlinx.android.synthetic.main.enter_thread_network_fragment.channelEd
30 import kotlinx.android.synthetic.main.enter_thread_network_fragment.masterKeyEd
31 import kotlinx.android.synthetic.main.enter_thread_network_fragment.panIdEd
32 import kotlinx.android.synthetic.main.enter_thread_network_fragment.xpanIdEd
33 import kotlinx.android.synthetic.main.enter_wifi_network_fragment.*
34 import kotlinx.android.synthetic.main.enter_wifi_network_fragment.view.*
37 * Fragment to collect Wi-Fi network information from user and send it to device being provisioned.
39 class EnterNetworkFragment : Fragment() {
41 private val networkType: ProvisionNetworkType
42 get() = requireNotNull(
43 ProvisionNetworkType.fromName(arguments?.getString(ARG_PROVISION_NETWORK_TYPE))
46 override fun onCreateView(
47 inflater: LayoutInflater,
48 container: ViewGroup?,
49 savedInstanceState: Bundle?
51 val layoutRes = when (networkType) {
52 ProvisionNetworkType.WIFI -> R.layout.enter_wifi_network_fragment
53 ProvisionNetworkType.THREAD -> R.layout.enter_thread_network_fragment
56 return inflater.inflate(layoutRes, container, false).apply {
57 saveNetworkBtn.setOnClickListener { onSaveNetworkClicked() }
61 private fun onSaveNetworkClicked() {
62 if (networkType == ProvisionNetworkType.WIFI) {
69 private fun saveWifiNetwork() {
70 val ssid = ssidEd.text
73 if (ssid.isNullOrBlank() || pwd.isNullOrBlank()) {
74 Toast.makeText(requireContext(), "Ssid and password required.", Toast.LENGTH_SHORT).show()
78 ChipClient.getDeviceController().apply {
79 sendWiFiCredentials(ssid.toString(), pwd.toString())
83 private fun saveThreadNetwork() {
84 val channelStr = channelEd.text
85 val panIdStr = panIdEd.text
87 if (channelStr.isNullOrBlank()) {
88 Toast.makeText(requireContext(), "Channel is empty", Toast.LENGTH_SHORT).show()
92 if (panIdStr.isNullOrBlank()) {
93 Toast.makeText(requireContext(), "PAN ID is empty", Toast.LENGTH_SHORT).show()
97 if (xpanIdEd.text.isNullOrBlank()) {
98 Toast.makeText(requireContext(), "XPAN ID is empty", Toast.LENGTH_SHORT).show()
102 val xpanIdStr = xpanIdEd.text.toString().filterNot { c -> c == ':' }
103 if (xpanIdStr.length != NUM_XPANID_BYTES * 2) {
104 Toast.makeText(requireContext(), "Extended PAN ID is invalid", Toast.LENGTH_SHORT).show()
108 if (masterKeyEd.text.isNullOrBlank()) {
109 Toast.makeText(requireContext(), "Master Key is empty", Toast.LENGTH_SHORT).show()
113 val masterKeyStr = masterKeyEd.text.toString().filterNot { c -> c == ':' }
114 if (masterKeyStr.length != NUM_MASTER_KEY_BYTES * 2) {
115 Toast.makeText(requireContext(), "Master key is invalid", Toast.LENGTH_SHORT).show()
119 ChipClient.getDeviceController().sendThreadCredentials(
120 channelStr.toString().toInt(),
121 panIdStr.toString().toInt(16),
122 xpanIdStr.hexToByteArray(),
123 masterKeyStr.hexToByteArray())
126 private fun String.hexToByteArray(): ByteArray {
127 return chunked(2).map{ byteStr -> byteStr.toUByte(16).toByte()}.toByteArray()
131 private const val TAG = "EnterNetworkFragment"
132 private const val ARG_PROVISION_NETWORK_TYPE = "provision_network_type"
133 private const val NUM_XPANID_BYTES = 8
134 private const val NUM_MASTER_KEY_BYTES = 16
136 fun newInstance(provisionNetworkType: ProvisionNetworkType): EnterNetworkFragment {
137 return EnterNetworkFragment().apply {
138 arguments = Bundle(1).apply {
139 putString(ARG_PROVISION_NETWORK_TYPE, provisionNetworkType.name)