1 /*
2  * Copyright (C) 2023 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.settings.connecteddevice.stylus;
18 
19 import android.content.Context;
20 import android.hardware.usb.UsbDevice;
21 import android.hardware.usb.UsbManager;
22 
23 import androidx.annotation.Nullable;
24 import androidx.annotation.VisibleForTesting;
25 import androidx.preference.Preference;
26 import androidx.preference.PreferenceCategory;
27 import androidx.preference.PreferenceScreen;
28 
29 import com.android.settings.core.BasePreferenceController;
30 import com.android.settings.overlay.FeatureFactory;
31 import com.android.settingslib.core.lifecycle.LifecycleObserver;
32 import com.android.settingslib.core.lifecycle.events.OnStart;
33 import com.android.settingslib.core.lifecycle.events.OnStop;
34 
35 import java.util.ArrayList;
36 import java.util.List;
37 
38 /** Preference controller for stylus firmware updates via USB **/
39 public class StylusUsbFirmwareController extends BasePreferenceController
40         implements LifecycleObserver, OnStart, OnStop {
41     private static final String TAG = StylusUsbFirmwareController.class.getSimpleName();
42     @Nullable
43     private UsbDevice mStylusUsbDevice;
44     private final UsbStylusBroadcastReceiver mUsbStylusBroadcastReceiver;
45 
46     private PreferenceScreen mPreferenceScreen;
47     private PreferenceCategory mPreference;
48 
49     @VisibleForTesting
50     UsbStylusBroadcastReceiver.UsbStylusConnectionListener mUsbConnectionListener =
51             (stylusUsbDevice, attached) -> {
52                 refresh();
53             };
54 
StylusUsbFirmwareController(Context context, String key)55     public StylusUsbFirmwareController(Context context, String key) {
56         super(context, key);
57         mUsbStylusBroadcastReceiver = new UsbStylusBroadcastReceiver(context,
58                 mUsbConnectionListener);
59     }
60 
61     @Override
displayPreference(PreferenceScreen screen)62     public void displayPreference(PreferenceScreen screen) {
63         mPreferenceScreen = screen;
64         refresh();
65         super.displayPreference(screen);
66     }
67 
68     @Override
getAvailabilityStatus()69     public int getAvailabilityStatus() {
70         // always available, preferences will be added or
71         // removed according to the connected usb device
72         return AVAILABLE;
73     }
74 
refresh()75     private void refresh() {
76         if (mPreferenceScreen == null) return;
77 
78         UsbDevice device = getStylusUsbDevice();
79         if (device == mStylusUsbDevice) {
80             return;
81         }
82         mStylusUsbDevice = device;
83         mPreference = mPreferenceScreen.findPreference(getPreferenceKey());
84         if (mPreference != null) {
85             mPreferenceScreen.removePreference(mPreference);
86         }
87         if (hasUsbStylusFirmwareUpdateFeature(mStylusUsbDevice)) {
88             StylusFeatureProvider featureProvider =
89                     FeatureFactory.getFeatureFactory().getStylusFeatureProvider();
90             List<Preference> preferences =
91                     featureProvider.getUsbFirmwareUpdatePreferences(mContext, mStylusUsbDevice);
92 
93             if (preferences != null) {
94                 mPreference = new PreferenceCategory(mContext);
95                 mPreference.setKey(getPreferenceKey());
96                 mPreferenceScreen.addPreference(mPreference);
97 
98                 for (Preference preference : preferences) {
99                     mPreference.addPreference(preference);
100                 }
101             }
102         }
103     }
104 
105     @Override
onStart()106     public void onStart() {
107         mUsbStylusBroadcastReceiver.register();
108     }
109 
110     @Override
onStop()111     public void onStop() {
112         mUsbStylusBroadcastReceiver.unregister();
113     }
114 
getStylusUsbDevice()115     private UsbDevice getStylusUsbDevice() {
116         UsbManager usbManager = mContext.getSystemService(UsbManager.class);
117 
118         if (usbManager == null) {
119             return null;
120         }
121 
122         List<UsbDevice> devices = new ArrayList<>(usbManager.getDeviceList().values());
123         if (devices.isEmpty()) {
124             return null;
125         }
126 
127         UsbDevice usbDevice = devices.get(0);
128         if (hasUsbStylusFirmwareUpdateFeature(usbDevice)) {
129             return usbDevice;
130         }
131         return null;
132     }
133 
hasUsbStylusFirmwareUpdateFeature(UsbDevice usbDevice)134     static boolean hasUsbStylusFirmwareUpdateFeature(UsbDevice usbDevice) {
135         if (usbDevice == null) return false;
136 
137         StylusFeatureProvider featureProvider =
138                 FeatureFactory.getFeatureFactory().getStylusFeatureProvider();
139 
140         return featureProvider.isUsbFirmwareUpdateEnabled(usbDevice);
141     }
142 }
143