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