1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.companiondevicesupport.feature.trust.ui; 18 19 import static com.android.car.connecteddevice.util.SafeLog.loge; 20 21 import android.annotation.NonNull; 22 import android.os.Bundle; 23 import android.text.Html; 24 import android.text.Spanned; 25 import android.view.LayoutInflater; 26 import android.view.View; 27 import android.view.ViewGroup; 28 import android.widget.Switch; 29 import android.widget.TextView; 30 31 import androidx.fragment.app.Fragment; 32 import androidx.lifecycle.ViewModelProviders; 33 34 import com.android.car.companiondevicesupport.R; 35 import com.android.car.companiondevicesupport.api.external.AssociatedDevice; 36 import com.android.car.companiondevicesupport.api.internal.trust.TrustedDevice; 37 38 import java.util.List; 39 40 /** Fragment that shows the details of an trusted device. */ 41 public class TrustedDeviceDetailFragment extends Fragment { 42 private final static String TAG = "TrustedDeviceDetailFragment"; 43 private final static String ASSOCIATED_DEVICE_KEY = "AssociatedDeviceKey"; 44 45 private AssociatedDevice mAssociatedDevice; 46 private TrustedDeviceViewModel mModel; 47 private TrustedDevice mTrustedDevice; 48 private Switch mSwitch; 49 private TextView mTrustedDeviceTitle; 50 newInstance(@onNull AssociatedDevice device)51 static TrustedDeviceDetailFragment newInstance(@NonNull AssociatedDevice device) { 52 Bundle bundle = new Bundle(); 53 bundle.putParcelable(ASSOCIATED_DEVICE_KEY, device); 54 TrustedDeviceDetailFragment fragment = new TrustedDeviceDetailFragment(); 55 fragment.setArguments(bundle); 56 return fragment; 57 } 58 59 @Override onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)60 public View onCreateView( 61 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 62 return inflater.inflate(R.layout.trusted_device_detail_fragment, container, false); 63 } 64 65 @Override onViewCreated(View view, Bundle savedInstanceState)66 public void onViewCreated(View view, Bundle savedInstanceState) { 67 Bundle bundle = getArguments(); 68 if (bundle == null) { 69 loge(TAG, "No valid arguments for TrustedDeviceDetailFragment."); 70 return; 71 } 72 mAssociatedDevice = bundle.getParcelable(ASSOCIATED_DEVICE_KEY); 73 mTrustedDeviceTitle = view.findViewById(R.id.trusted_device_item_title); 74 setTrustedDeviceTitle(); 75 mModel = ViewModelProviders.of(getActivity()).get(TrustedDeviceViewModel.class); 76 mSwitch = view.findViewById(R.id.trusted_device_switch); 77 mSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { 78 if (isChecked && mTrustedDevice == null) { 79 // When the current device has not been enrolled as trusted device, turning on the 80 // switch is for enrolling the current device. 81 mModel.setDeviceToEnable(mAssociatedDevice); 82 mSwitch.setChecked(false); 83 } else if (!isChecked && mTrustedDevice != null) { 84 // When the current device has been enrolled as trusted device, turning off the 85 // switch is for disable trusted device feature for the current device. 86 mModel.setDeviceToDisable(mTrustedDevice); 87 mSwitch.setChecked(true); 88 } 89 // Ignore other conditions as {@link Switch#setChecked(boolean)} will always trigger 90 // this listener. 91 }); 92 observeViewModel(); 93 } 94 setTrustedDeviceTitle()95 private void setTrustedDeviceTitle() { 96 String deviceName = mAssociatedDevice.getDeviceName(); 97 if (deviceName == null) { 98 deviceName = getString(R.string.unknown); 99 } 100 String deviceTitle = getString(R.string.trusted_device_item_title, deviceName); 101 Spanned styledDeviceTitle = Html.fromHtml(deviceTitle, Html.FROM_HTML_MODE_LEGACY); 102 mTrustedDeviceTitle.setText(styledDeviceTitle); 103 } 104 setTrustedDevices(List<TrustedDevice> devices)105 private void setTrustedDevices(List<TrustedDevice> devices) { 106 if (devices == null) { 107 mSwitch.setChecked(false); 108 mTrustedDevice = null; 109 return; 110 } 111 if (devices.isEmpty()) { 112 mSwitch.setChecked(false); 113 mTrustedDevice = null; 114 return; 115 } 116 if (devices.size() > 1) { 117 loge(TAG, "More than one devices have been associated."); 118 return; 119 } 120 // Currently, we only support single trusted device. 121 TrustedDevice device = devices.get(0); 122 if (!device.getDeviceId().equals(mAssociatedDevice.getDeviceId())) { 123 loge(TAG, "Trusted device id doesn't match associated device id."); 124 return; 125 } 126 mTrustedDevice = device; 127 mSwitch.setChecked(true); 128 } 129 observeViewModel()130 private void observeViewModel() { 131 mModel.getAssociatedDevice().observe(this, device -> { 132 if (device == null) { 133 return; 134 } 135 if (device.getDeviceId().equals(mAssociatedDevice.getDeviceId())) { 136 mAssociatedDevice = device; 137 setTrustedDeviceTitle(); 138 } 139 }); 140 141 mModel.getTrustedDevices().observe(this, this::setTrustedDevices); 142 143 mModel.getDisabledDevice().observe(this, device -> { 144 if (device == null) { 145 return; 146 } 147 mModel.setDisabledDevice(null); 148 if (mTrustedDevice.equals(device)) { 149 mTrustedDevice = null; 150 mSwitch.setChecked(false); 151 } 152 }); 153 154 mModel.getEnabledDevice().observe(this, device -> { 155 if (device == null) { 156 return; 157 } 158 mModel.setEnabledDevice(null); 159 if (device.getDeviceId().equals(mAssociatedDevice.getDeviceId())) { 160 mTrustedDevice = device; 161 mSwitch.setChecked(true); 162 } 163 }); 164 } 165 } 166