1 /*
2  * Copyright (C) 2017 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 package com.android.settings.connecteddevice.usb;
17 
18 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
19 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
20 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
21 
22 import static com.android.settingslib.RestrictedLockUtilsInternal.checkIfUsbDataSignalingIsDisabled;
23 
24 import android.content.Context;
25 import android.hardware.usb.UsbManager;
26 import android.os.UserHandle;
27 
28 import androidx.annotation.VisibleForTesting;
29 import androidx.preference.Preference;
30 
31 import com.android.settings.R;
32 import com.android.settings.connecteddevice.DevicePreferenceCallback;
33 import com.android.settings.core.SubSettingLauncher;
34 import com.android.settings.dashboard.DashboardFragment;
35 import com.android.settings.overlay.FeatureFactory;
36 import com.android.settingslib.RestrictedPreference;
37 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
38 
39 /**
40  * Controller to maintain connected usb device
41  */
42 public class ConnectedUsbDeviceUpdater {
43 
44     private static final String PREF_KEY = "connected_usb";
45 
46     private final MetricsFeatureProvider mMetricsFeatureProvider;
47 
48     private DashboardFragment mFragment;
49     private UsbBackend mUsbBackend;
50     private DevicePreferenceCallback mDevicePreferenceCallback;
51     @VisibleForTesting
52     RestrictedPreference mUsbPreference;
53     @VisibleForTesting
54     UsbConnectionBroadcastReceiver mUsbReceiver;
55 
56     @VisibleForTesting
57     UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener =
58             (connected, functions, powerRole, dataRole) -> {
59                 if (connected) {
60                     mUsbPreference.setSummary(getSummary(dataRole == DATA_ROLE_DEVICE
61                                     ? functions : UsbManager.FUNCTION_NONE, powerRole));
62                     mDevicePreferenceCallback.onDeviceAdded(mUsbPreference);
63                 } else {
64                     mDevicePreferenceCallback.onDeviceRemoved(mUsbPreference);
65                 }
66             };
67 
ConnectedUsbDeviceUpdater(Context context, DashboardFragment fragment, DevicePreferenceCallback devicePreferenceCallback)68     public ConnectedUsbDeviceUpdater(Context context, DashboardFragment fragment,
69             DevicePreferenceCallback devicePreferenceCallback) {
70         this(context, fragment, devicePreferenceCallback, new UsbBackend(context));
71     }
72 
73     @VisibleForTesting
ConnectedUsbDeviceUpdater(Context context, DashboardFragment fragment, DevicePreferenceCallback devicePreferenceCallback, UsbBackend usbBackend)74     ConnectedUsbDeviceUpdater(Context context, DashboardFragment fragment,
75             DevicePreferenceCallback devicePreferenceCallback, UsbBackend usbBackend) {
76         mFragment = fragment;
77         mDevicePreferenceCallback = devicePreferenceCallback;
78         mUsbBackend = usbBackend;
79         mUsbReceiver = new UsbConnectionBroadcastReceiver(context,
80                 mUsbConnectionListener, mUsbBackend);
81         mMetricsFeatureProvider = FeatureFactory.getFactory(mFragment.getContext())
82                 .getMetricsFeatureProvider();
83     }
84 
registerCallback()85     public void registerCallback() {
86         // This method could handle multiple register
87         mUsbReceiver.register();
88     }
89 
unregisterCallback()90     public void unregisterCallback() {
91         mUsbReceiver.unregister();
92     }
93 
initUsbPreference(Context context)94     public void initUsbPreference(Context context) {
95         mUsbPreference = new RestrictedPreference(context, null /* AttributeSet */);
96         mUsbPreference.setTitle(R.string.usb_pref);
97         mUsbPreference.setIcon(R.drawable.ic_usb);
98         mUsbPreference.setKey(PREF_KEY);
99         mUsbPreference.setDisabledByAdmin(
100                 checkIfUsbDataSignalingIsDisabled(context, UserHandle.myUserId()));
101         mUsbPreference.setOnPreferenceClickListener((Preference p) -> {
102             mMetricsFeatureProvider.logClickedPreference(p, mFragment.getMetricsCategory());
103             // New version - uses a separate screen.
104             new SubSettingLauncher(mFragment.getContext())
105                     .setDestination(UsbDetailsFragment.class.getName())
106                     .setTitleRes(R.string.usb_preference)
107                     .setSourceMetricsCategory(mFragment.getMetricsCategory())
108                     .launch();
109             return true;
110         });
111 
112         forceUpdate();
113     }
114 
forceUpdate()115     private void forceUpdate() {
116         // Register so we can get the connection state from sticky intent.
117         //TODO(b/70336520): Use an API to get data instead of sticky intent
118         mUsbReceiver.register();
119     }
120 
getSummary(long functions, int power)121     public static int getSummary(long functions, int power) {
122         switch (power) {
123             case POWER_ROLE_SINK:
124                 if (functions == UsbManager.FUNCTION_MTP) {
125                     return R.string.usb_summary_file_transfers;
126                 } else if (functions == UsbManager.FUNCTION_RNDIS) {
127                     return R.string.usb_summary_tether;
128                 } else if (functions == UsbManager.FUNCTION_PTP) {
129                     return R.string.usb_summary_photo_transfers;
130                 } else if (functions == UsbManager.FUNCTION_MIDI) {
131                     return R.string.usb_summary_MIDI;
132                 } else {
133                     return R.string.usb_summary_charging_only;
134                 }
135             case POWER_ROLE_SOURCE:
136                 if (functions == UsbManager.FUNCTION_MTP) {
137                     return R.string.usb_summary_file_transfers_power;
138                 } else if (functions == UsbManager.FUNCTION_RNDIS) {
139                     return R.string.usb_summary_tether_power;
140                 } else if (functions == UsbManager.FUNCTION_PTP) {
141                     return R.string.usb_summary_photo_transfers_power;
142                 } else if (functions == UsbManager.FUNCTION_MIDI) {
143                     return R.string.usb_summary_MIDI_power;
144                 } else {
145                     return R.string.usb_summary_power_only;
146                 }
147             default:
148                 return R.string.usb_summary_charging_only;
149         }
150     }
151 }
152