| /* |
| * Copyright (c) 2020 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. |
| * |
| */ |
| package com.google.chip.chiptool |
| |
| import android.Manifest |
| import android.content.pm.PackageManager |
| import android.os.Build |
| import android.os.Bundle |
| import android.view.LayoutInflater |
| import android.view.View |
| import android.view.ViewGroup |
| import androidx.activity.result.contract.ActivityResultContracts |
| import androidx.appcompat.app.AlertDialog |
| import androidx.core.content.ContextCompat |
| import androidx.fragment.app.Fragment |
| import com.google.chip.chiptool.attestation.AttestationTestFragment |
| import com.google.chip.chiptool.clusterclient.* |
| import com.google.chip.chiptool.clusterclient.clusterinteraction.ClusterInteractionFragment |
| import com.google.chip.chiptool.databinding.SelectActionFragmentBinding |
| import com.google.chip.chiptool.provisioning.ProvisionNetworkType |
| import com.google.chip.chiptool.provisioning.UnpairDeviceFragment |
| import com.google.chip.chiptool.setuppayloadscanner.BarcodeFragment |
| import com.google.chip.chiptool.util.FragmentUtil |
| |
| /** Fragment to select from various options to interact with a CHIP device. */ |
| class SelectActionFragment : Fragment() { |
| private var _binding: SelectActionFragmentBinding? = null |
| private val binding get() = _binding!! |
| |
| override fun onCreateView( |
| inflater: LayoutInflater, |
| container: ViewGroup?, |
| savedInstanceState: Bundle? |
| ): View { |
| _binding = SelectActionFragmentBinding.inflate(inflater, container, false) |
| |
| binding.provisionWiFiCredentialsBtn.apply { |
| isEnabled = hasLocationPermission() |
| setOnClickListener { handleProvisionWiFiCredentialsClicked() } |
| } |
| |
| binding.provisionThreadCredentialsBtn.apply { |
| isEnabled = hasLocationPermission() |
| setOnClickListener { handleProvisionThreadCredentialsClicked() } |
| } |
| |
| binding.scanQrBtn.setOnClickListener { handleScanQrCodeClicked() } |
| binding.onOffClusterBtn.setOnClickListener { handleOnOffClicked() } |
| binding.sensorClustersBtn.setOnClickListener { handleSensorClicked() } |
| binding.multiAdminClusterBtn.setOnClickListener { handleMultiAdminClicked() } |
| binding.opCredClustersBtn.setOnClickListener { handleOpCredClicked() } |
| binding.basicClusterBtn.setOnClickListener { handleBasicClicked() } |
| binding.attestationTestBtn.setOnClickListener { handleAttestationTestClicked() } |
| binding.clusterInteractionBtn.setOnClickListener { handleClusterInteractionClicked() } |
| binding.provisionCustomFlowBtn.setOnClickListener{ handleProvisionCustomFlowClicked() } |
| binding.wildcardBtn.setOnClickListener { handleWildcardClicked() } |
| binding.unpairDeviceBtn.setOnClickListener{ handleUnpairDeviceClicked() } |
| |
| return binding.root |
| } |
| |
| override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| super.onViewCreated(view, savedInstanceState) |
| |
| if (savedInstanceState != null) return |
| if (hasLocationPermission()) return |
| |
| val permissionRequest = |
| registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { grantResults |
| -> |
| var granted = true |
| for (value in grantResults.values) { |
| if (!value) { |
| granted = false |
| } |
| } |
| if (granted) { |
| binding.provisionWiFiCredentialsBtn.isEnabled = true |
| binding.provisionThreadCredentialsBtn.isEnabled = true |
| } else { |
| binding.provisionWiFiCredentialsBtn.isEnabled = false |
| binding.provisionThreadCredentialsBtn.isEnabled = false |
| |
| AlertDialog.Builder(requireContext()) |
| .setTitle(R.string.location_permission_denied_title) |
| .setMessage(R.string.location_permission_denied_message) |
| .setPositiveButton(R.string.text_ok) { dialog, _ -> dialog.dismiss() } |
| .setCancelable(false) |
| .create() |
| .show() |
| } |
| } |
| |
| val permissions: Array<String> = |
| if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { |
| arrayOf( |
| Manifest.permission.BLUETOOTH_SCAN, |
| Manifest.permission.BLUETOOTH_CONNECT, |
| Manifest.permission.ACCESS_FINE_LOCATION, |
| ) |
| } else { |
| arrayOf(Manifest.permission.ACCESS_FINE_LOCATION) |
| } |
| permissionRequest.launch(permissions) |
| } |
| |
| override fun onDestroyView() { |
| super.onDestroyView() |
| _binding = null |
| } |
| |
| private fun hasLocationPermission(): Boolean { |
| val locationPermissionGranted = |
| ContextCompat.checkSelfPermission( |
| requireContext(), |
| Manifest.permission.ACCESS_FINE_LOCATION |
| ) == PackageManager.PERMISSION_GRANTED |
| |
| // Android 12 new permission |
| var bleScanPermissionGranted = true |
| if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { |
| bleScanPermissionGranted = |
| ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.BLUETOOTH_SCAN) == |
| PackageManager.PERMISSION_GRANTED |
| } |
| |
| return locationPermissionGranted && bleScanPermissionGranted |
| } |
| |
| private fun getCallback() = FragmentUtil.getHost(this, Callback::class.java) |
| |
| /** Interface for notifying the host. */ |
| interface Callback { |
| /** Notifies listener of a click to manually input the CHIP device address. */ |
| fun onShowDeviceAddressInput() |
| |
| fun SetNetworkType(type: ProvisionNetworkType) |
| } |
| |
| private fun showFragment(fragment: Fragment, showOnBack: Boolean = true) { |
| val fragmentTransaction = parentFragmentManager |
| .beginTransaction() |
| .replace(R.id.nav_host_fragment, fragment, fragment.javaClass.simpleName) |
| |
| if (showOnBack) { |
| fragmentTransaction.addToBackStack(null) |
| } |
| |
| fragmentTransaction.commit() |
| } |
| |
| /** |
| * Notifies listener of Scan QR code button click. |
| */ |
| private fun handleScanQrCodeClicked() { |
| showFragment(BarcodeFragment.newInstance(), false) |
| } |
| |
| /** |
| * Notifies listener of Light On/Off & Level Cluster button click. |
| */ |
| private fun handleOnOffClicked() { |
| showFragment(OnOffClientFragment.newInstance()) |
| } |
| |
| /** |
| * Notifies listener of Sensor Clusters button click. |
| */ |
| private fun handleSensorClicked() { |
| showFragment(SensorClientFragment.newInstance()) |
| } |
| |
| /** |
| * Notifies listener of Multi-admin Clusters button click. |
| */ |
| private fun handleMultiAdminClicked() { |
| showFragment(MultiAdminClientFragment.newInstance()) |
| } |
| |
| /** |
| * Notifies listener of Operational Credentials Clusters button click. |
| */ |
| private fun handleOpCredClicked() { |
| showFragment(OpCredClientFragment.newInstance()) |
| } |
| |
| /** |
| * Notifies listener of Basic Clusters button click. |
| */ |
| private fun handleBasicClicked() { |
| showFragment(BasicClientFragment.newInstance()) |
| } |
| |
| /** |
| * Notifies listener of attestation command button clicked. |
| */ |
| private fun handleAttestationTestClicked() { |
| showFragment(AttestationTestFragment.newInstance()) |
| } |
| |
| /** |
| * Notifies listener of cluster interaction button click. |
| */ |
| private fun handleClusterInteractionClicked() { |
| showFragment(ClusterInteractionFragment.newInstance()) |
| } |
| |
| /** |
| * Notifies listener of wildcard button click. |
| */ |
| private fun handleWildcardClicked() { |
| showFragment(WildcardFragment.newInstance()) |
| } |
| |
| /** |
| * Notifies listener of unpair button click. |
| */ |
| private fun handleUnpairDeviceClicked() { |
| showFragment(UnpairDeviceFragment.newInstance()) |
| } |
| |
| /** |
| * Notifies listener of provision-WiFi-credentials button click. |
| */ |
| private fun handleProvisionWiFiCredentialsClicked() { |
| getCallback()?.SetNetworkType(ProvisionNetworkType.WIFI) |
| showFragment(BarcodeFragment.newInstance(), false) |
| } |
| |
| /** |
| * Notifies listener of provision-Thread-credentials button click. |
| */ |
| private fun handleProvisionThreadCredentialsClicked() { |
| getCallback()?.SetNetworkType(ProvisionNetworkType.THREAD) |
| showFragment(BarcodeFragment.newInstance(), false) |
| } |
| |
| /** |
| * Notifies listener of provision-custom-flow button click. |
| */ |
| private fun handleProvisionCustomFlowClicked() { |
| showFragment(BarcodeFragment.newInstance(), false) |
| } |
| |
| companion object { |
| |
| @JvmStatic fun newInstance() = SelectActionFragment() |
| } |
| } |