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