1 /*
2  * Copyright (C) 2021 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.usb;
18 
19 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
20 
21 import android.content.Context;
22 import android.hardware.usb.UsbManager;
23 import android.os.SystemProperties;
24 
25 import androidx.preference.Preference;
26 import androidx.preference.PreferenceCategory;
27 import androidx.preference.PreferenceScreen;
28 import androidx.preference.SwitchPreferenceCompat;
29 import androidx.preference.TwoStatePreference;
30 
31 import com.android.settings.R;
32 import com.android.settings.Utils;
33 
34 /**
35  * This class controls the switch for setting if we should transcode files transferred via MTP over
36  * USB.
37  */
38 public class UsbDetailsTranscodeMtpController extends UsbDetailsController
39         implements Preference.OnPreferenceClickListener {
40     private static final String TRANSCODE_MTP_SYS_PROP_KEY = "sys.fuse.transcode_mtp";
41     private static final String PREFERENCE_KEY = "usb_transcode_mtp";
42     private static final String KEY_USB_TRANSCODE_FILES = "usb_transcode_files";
43 
44     private PreferenceCategory mPreferenceCategory;
45     private TwoStatePreference mSwitchPreference;
46 
UsbDetailsTranscodeMtpController(Context context, UsbDetailsFragment fragment, UsbBackend backend)47     public UsbDetailsTranscodeMtpController(Context context, UsbDetailsFragment fragment,
48             UsbBackend backend) {
49         super(context, fragment, backend);
50     }
51 
52 
53     @Override
displayPreference(PreferenceScreen screen)54     public void displayPreference(PreferenceScreen screen) {
55         super.displayPreference(screen);
56         mPreferenceCategory = screen.findPreference(getPreferenceKey());
57         mSwitchPreference = new SwitchPreferenceCompat(mPreferenceCategory.getContext());
58         mSwitchPreference.setTitle(R.string.usb_transcode_files);
59         mSwitchPreference.setKey(KEY_USB_TRANSCODE_FILES);
60         mSwitchPreference.setOnPreferenceClickListener(this);
61         mSwitchPreference.setSummaryOn(R.string.usb_transcode_files_summary);
62         mPreferenceCategory.addPreference(mSwitchPreference);
63     }
64 
65     @Override
refresh(boolean connected, long functions, int powerRole, int dataRole)66     protected void refresh(boolean connected, long functions, int powerRole, int dataRole) {
67         if (mUsbBackend.areFunctionsSupported(UsbManager.FUNCTION_MTP | UsbManager.FUNCTION_PTP)) {
68             mFragment.getPreferenceScreen().addPreference(mPreferenceCategory);
69         } else {
70             mFragment.getPreferenceScreen().removePreference(mPreferenceCategory);
71         }
72 
73         mSwitchPreference.setChecked(
74                 SystemProperties.getBoolean(TRANSCODE_MTP_SYS_PROP_KEY, false));
75         mPreferenceCategory.setEnabled(
76                 connected && isDeviceInFileTransferMode(functions, dataRole));
77     }
78 
79     @Override
onPreferenceClick(Preference preference)80     public boolean onPreferenceClick(Preference preference) {
81         requireAuthAndExecute(() -> {
82             SystemProperties.set(TRANSCODE_MTP_SYS_PROP_KEY,
83                     Boolean.toString(mSwitchPreference.isChecked()));
84 
85             final long previousFunctions = mUsbBackend.getCurrentFunctions();
86             // Toggle the MTP connection to reload file sizes for files shared via MTP clients
87             mUsbBackend.setCurrentFunctions(previousFunctions & ~UsbManager.FUNCTION_MTP);
88             mUsbBackend.setCurrentFunctions(previousFunctions);
89         });
90 
91         return true;
92     }
93 
94     @Override
isAvailable()95     public boolean isAvailable() {
96         return !Utils.isMonkeyRunning();
97     }
98 
99     @Override
getPreferenceKey()100     public String getPreferenceKey() {
101         return PREFERENCE_KEY;
102     }
103 
isDeviceInFileTransferMode(long functions, int dataRole)104     private static boolean isDeviceInFileTransferMode(long functions, int dataRole) {
105         return dataRole == DATA_ROLE_DEVICE && ((functions & UsbManager.FUNCTION_MTP) != 0
106                 || (functions & UsbManager.FUNCTION_PTP) != 0);
107     }
108 }
109