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 android.content.BroadcastReceiver; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.IntentFilter; 22 import android.hardware.usb.UsbManager; 23 import android.hardware.usb.UsbPortStatus; 24 import android.util.Log; 25 26 import com.android.settingslib.core.lifecycle.LifecycleObserver; 27 import com.android.settingslib.core.lifecycle.events.OnPause; 28 import com.android.settingslib.core.lifecycle.events.OnResume; 29 30 /** 31 * Receiver to receive usb update and use {@link UsbConnectionListener} to invoke callback 32 */ 33 public class UsbConnectionBroadcastReceiver extends BroadcastReceiver implements LifecycleObserver, 34 OnResume, OnPause { 35 private static final String TAG = "UsbBroadcastReceiver"; 36 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 37 38 private Context mContext; 39 private UsbConnectionListener mUsbConnectionListener; 40 private boolean mListeningToUsbEvents; 41 private UsbBackend mUsbBackend; 42 43 private boolean mConnected; 44 private long mFunctions; 45 private int mDataRole; 46 private int mPowerRole; 47 UsbConnectionBroadcastReceiver(Context context, UsbConnectionListener usbConnectionListener, UsbBackend backend)48 public UsbConnectionBroadcastReceiver(Context context, 49 UsbConnectionListener usbConnectionListener, UsbBackend backend) { 50 mContext = context; 51 mUsbConnectionListener = usbConnectionListener; 52 mUsbBackend = backend; 53 54 mFunctions = UsbManager.FUNCTION_NONE; 55 mDataRole = UsbPortStatus.DATA_ROLE_NONE; 56 mPowerRole = UsbPortStatus.POWER_ROLE_NONE; 57 } 58 59 @Override onReceive(Context context, Intent intent)60 public void onReceive(Context context, Intent intent) { 61 if (DEBUG) { 62 Log.d(TAG, "onReceive() action : " + intent.getAction()); 63 } 64 boolean isUsbConfigured = intent.getExtras() != null 65 ? intent.getExtras().getBoolean(UsbManager.USB_CONFIGURED) : false; 66 if (UsbManager.ACTION_USB_STATE.equals(intent.getAction())) { 67 mConnected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED) 68 || intent.getExtras().getBoolean(UsbManager.USB_HOST_CONNECTED); 69 long functions = UsbManager.FUNCTION_NONE; 70 if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_MTP) 71 && intent.getExtras().getBoolean(UsbManager.USB_DATA_UNLOCKED, false)) { 72 functions |= UsbManager.FUNCTION_MTP; 73 } 74 if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_PTP) 75 && intent.getExtras().getBoolean(UsbManager.USB_DATA_UNLOCKED, false)) { 76 functions |= UsbManager.FUNCTION_PTP; 77 } 78 if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_MIDI)) { 79 functions |= UsbManager.FUNCTION_MIDI; 80 } 81 if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_RNDIS)) { 82 functions |= UsbManager.FUNCTION_RNDIS; 83 } 84 if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_ACCESSORY)) { 85 functions |= UsbManager.FUNCTION_ACCESSORY; 86 } 87 if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_NCM)) { 88 functions |= UsbManager.FUNCTION_NCM; 89 } 90 if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_UVC)) { 91 functions |= UsbManager.FUNCTION_UVC; 92 } 93 mFunctions = functions; 94 mDataRole = mUsbBackend.getDataRole(); 95 mPowerRole = mUsbBackend.getPowerRole(); 96 } else if (UsbManager.ACTION_USB_PORT_CHANGED.equals(intent.getAction())) { 97 UsbPortStatus portStatus = intent.getExtras() 98 .getParcelable(UsbManager.EXTRA_PORT_STATUS); 99 if (portStatus != null) { 100 mDataRole = portStatus.getCurrentDataRole(); 101 mPowerRole = portStatus.getCurrentPowerRole(); 102 } 103 } 104 if (mUsbConnectionListener != null) { 105 mUsbConnectionListener.onUsbConnectionChanged(mConnected, mFunctions, mPowerRole, 106 mDataRole, isUsbConfigured); 107 } 108 } 109 register()110 public void register() { 111 if (!mListeningToUsbEvents) { 112 mConnected = false; 113 final IntentFilter intentFilter = new IntentFilter(); 114 intentFilter.addAction(UsbManager.ACTION_USB_STATE); 115 intentFilter.addAction(UsbManager.ACTION_USB_PORT_CHANGED); 116 final Intent intent = mContext.registerReceiver(this, intentFilter); 117 // TODO b/77240599 use an api instead of sticky intent 118 if (intent != null) { 119 onReceive(mContext, intent); 120 } 121 mListeningToUsbEvents = true; 122 } 123 } 124 unregister()125 public void unregister() { 126 if (mListeningToUsbEvents) { 127 mContext.unregisterReceiver(this); 128 mListeningToUsbEvents = false; 129 } 130 } 131 isConnected()132 public boolean isConnected() { 133 return mConnected; 134 } 135 136 @Override onResume()137 public void onResume() { 138 register(); 139 } 140 141 @Override onPause()142 public void onPause() { 143 unregister(); 144 } 145 146 /** 147 * Interface definition for a callback to be invoked when usb connection is changed. 148 */ 149 interface UsbConnectionListener { onUsbConnectionChanged(boolean connected, long functions, int powerRole, int dataRole, boolean isUsbConfigured)150 void onUsbConnectionChanged(boolean connected, long functions, int powerRole, int dataRole, 151 boolean isUsbConfigured); 152 } 153 } 154