1d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan/* 2d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * Copyright (C) 2016 The Android Open Source Project 3d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * 4d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * Licensed under the Apache License, Version 2.0 (the "License"); 5d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * you may not use this file except in compliance with the License. 6d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * You may obtain a copy of the License at 7d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * 8d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * http://www.apache.org/licenses/LICENSE-2.0 9d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * 10d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * Unless required by applicable law or agreed to in writing, software 11d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * distributed under the License is distributed on an "AS IS" BASIS, 12d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * See the License for the specific language governing permissions and 14d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * limitations under the License. 15d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan */ 16d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanpackage android.car.usb.handler; 17d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 18d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport android.content.BroadcastReceiver; 19d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport android.content.Context; 20d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport android.content.Intent; 21d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport android.content.IntentFilter; 22d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport android.hardware.usb.UsbDevice; 23d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport android.hardware.usb.UsbManager; 24d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport android.os.Handler; 25d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport android.os.Looper; 26d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport android.os.Message; 27d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport android.util.Log; 28d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport com.android.internal.annotations.GuardedBy; 29d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport java.util.ArrayList; 30d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanimport java.util.List; 31d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 32d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan/** 33d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * Controller used to handle USB device connections. 34d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * TODO: Support handling multiple new USB devices at the same time. 35d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan */ 36d428549b58b2df5015bff81d79747265ee8be536Kevin Crossanpublic final class UsbHostController 37d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan implements UsbDeviceHandlerResolver.UsbDeviceHandlerResolverCallback { 38d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 39d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan /** 40d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * Callbacks for controller 41d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan */ 42d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan public interface UsbHostControllerCallbacks { 43d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan /** Host controller ready for shutdown */ 44d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan void shutdown(); 45d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan /** Change of processing state */ 46d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan void processingStateChanged(boolean processing); 47d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan /** Title of processing changed */ 48d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan void titleChanged(String title); 49d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan /** Options for USB device changed */ 50d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan void optionsUpdated(List<UsbDeviceSettings> options); 51d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 52d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 53d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private static final String TAG = UsbHostController.class.getSimpleName(); 54d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private static final boolean LOCAL_LOGD = true; 55d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private static final boolean LOCAL_LOGV = true; 56d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 57d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 58d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private final List<UsbDeviceSettings> mEmptyList = new ArrayList<>(); 59d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private final Context mContext; 60d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private final UsbHostControllerCallbacks mCallback; 61d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private final UsbSettingsStorage mUsbSettingsStorage; 62d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private final UsbManager mUsbManager; 63d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private final UsbDeviceHandlerResolver mUsbResolver; 64d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private final UsbHostControllerHandler mHandler; 65d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 66d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private final BroadcastReceiver mUsbBroadcastReceiver = new BroadcastReceiver() { 67d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan @Override 68d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan public void onReceive(Context context, Intent intent) { 69d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) { 70d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE); 714f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan unsetActiveDeviceIfMatch(device); 72d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) { 73d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE); 744f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan setActiveDeviceIfMatch(device); 75d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 76d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 77d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan }; 78d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 79d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan @GuardedBy("this") 80d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private UsbDevice mActiveDevice; 81d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 82d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan public UsbHostController(Context context, UsbHostControllerCallbacks callbacks) { 83d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mContext = context; 84d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mCallback = callbacks; 85d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mHandler = new UsbHostControllerHandler(Looper.myLooper()); 86d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mUsbSettingsStorage = new UsbSettingsStorage(context); 87d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); 88d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mUsbResolver = new UsbDeviceHandlerResolver(mUsbManager, mContext, this); 89d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan IntentFilter filter = new IntentFilter(); 90d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); 91d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); 92d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan context.registerReceiver(mUsbBroadcastReceiver, filter); 93d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 94d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 95d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 964f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan private synchronized void setActiveDeviceIfMatch(UsbDevice device) { 974f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan if (mActiveDevice != null && device != null 984f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan && UsbUtil.isDevicesMatching(device, mActiveDevice)) { 99d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mActiveDevice = device; 100d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 101d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 102d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 1034f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan private synchronized void unsetActiveDeviceIfMatch(UsbDevice device) { 104d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mHandler.requestDeviceRemoved(); 1054f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan if (mActiveDevice != null && device != null 1064f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan && UsbUtil.isDevicesMatching(device, mActiveDevice)) { 107d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mActiveDevice = null; 108d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 109d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 110d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 111d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private synchronized boolean startDeviceProcessingIfNull(UsbDevice device) { 112d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan if (mActiveDevice == null) { 113d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mActiveDevice = device; 114d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan return true; 115d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 116d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan return false; 117d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 118d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 119d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private synchronized void stopDeviceProcessing() { 120d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mActiveDevice = null; 121d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 122d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 123d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private synchronized UsbDevice getActiveDevice() { 124d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan return mActiveDevice; 125d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 126d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 127d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private boolean deviceMatchedActiveDevice(UsbDevice device) { 128d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan UsbDevice activeDevice = getActiveDevice(); 1294f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan return activeDevice != null && UsbUtil.isDevicesMatching(activeDevice, device); 1304f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan } 1314f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan 1324f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan private String generateTitle() { 1334f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan String manufacturer = mActiveDevice.getManufacturerName(); 1344f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan String product = mActiveDevice.getProductName(); 1354f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan if (manufacturer == null && product == null) { 1364f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan return mContext.getString(R.string.usb_unknown_device); 1374f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan } 1384f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan if (manufacturer != null && product != null) { 1394f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan return manufacturer + " " + product; 1404f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan } 1414f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan if (manufacturer != null) { 1424f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan return manufacturer; 1434f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan } 1444f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan return product; 145d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 146d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 147d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan /** 148d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * Processes device new device. 149d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * <p> 150d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * It will load existing settings or resolve supported handlers. 151d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan */ 152d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan public void processDevice(UsbDevice device) { 153d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan if (!startDeviceProcessingIfNull(device)) { 154d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan Log.w(TAG, "Currently, other device is being processed"); 155d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 156d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mCallback.optionsUpdated(mEmptyList); 157d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mCallback.processingStateChanged(true); 158d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 1594f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan UsbDeviceSettings settings = mUsbSettingsStorage.getSettings(device); 160d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan if (settings != null && mUsbResolver.dispatch( 161d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mActiveDevice, settings.getHandler(), settings.getAoap())) { 162d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan if (LOCAL_LOGV) { 163d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan Log.v(TAG, "Usb Device: " + device + " was sent to component: " 164d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan + settings.getHandler()); 165d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 166d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan return; 167d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 1684f208d8be0fd9cbf1d9defb0587507f11a092b98Kevin Crossan mCallback.titleChanged(generateTitle()); 169d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mUsbResolver.resolve(device); 170d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 171d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 172d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan /** 173d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * Applies device settings. 174d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan */ 175d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan public void applyDeviceSettings(UsbDeviceSettings settings) { 176d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mUsbSettingsStorage.saveSettings(settings); 177d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mUsbResolver.dispatch(getActiveDevice(), settings.getHandler(), settings.getAoap()); 178d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 179d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 180d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan /** 181d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan * Release object. 182d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan */ 183d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan public void release() { 184d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mContext.unregisterReceiver(mUsbBroadcastReceiver); 185d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mUsbResolver.release(); 186d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 187d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 188d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan @Override 189d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan public void onHandlersResolveCompleted( 190d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan UsbDevice device, List<UsbDeviceSettings> handlers) { 191d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan if (LOCAL_LOGD) { 192d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan Log.d(TAG, "onHandlersResolveComplete: " + device); 193d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 194d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan if (deviceMatchedActiveDevice(device)) { 195d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mCallback.processingStateChanged(false); 196d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan if (handlers.isEmpty()) { 197d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan onDeviceDispatched(); 198d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } else if (handlers.size() == 1) { 199d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan applyDeviceSettings(handlers.get(0)); 200d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } else { 201d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mCallback.optionsUpdated(handlers); 202d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 203d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } else { 204d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan Log.w(TAG, "Handlers ignored as they came for inactive device"); 205d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 206d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 207d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 208d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan @Override 209d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan public void onDeviceDispatched() { 210d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan stopDeviceProcessing(); 211d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mCallback.shutdown(); 212d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 213d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 214d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan void doHandleDeviceRemoved() { 215d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan if (getActiveDevice() == null) { 216d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan if (LOCAL_LOGD) { 217d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan Log.d(TAG, "USB device detached"); 218d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 219d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan stopDeviceProcessing(); 220d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan mCallback.shutdown(); 221d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 222d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 223d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 224d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private class UsbHostControllerHandler extends Handler { 225d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private static final int MSG_DEVICE_REMOVED = 1; 226d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 227d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private static final int DEVICE_REMOVE_TIMEOUT_MS = 500; 228d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 229d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private UsbHostControllerHandler(Looper looper) { 230d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan super(looper); 231d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 232d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 233d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan private void requestDeviceRemoved() { 234d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan sendEmptyMessageDelayed(MSG_DEVICE_REMOVED, DEVICE_REMOVE_TIMEOUT_MS); 235d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 236d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 237d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan @Override 238d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan public void handleMessage(Message msg) { 239d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan switch (msg.what) { 240d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan case MSG_DEVICE_REMOVED: 241d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan doHandleDeviceRemoved(); 242d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan break; 243d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan default: 244d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan Log.w(TAG, "Unhandled message: " + msg); 245d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan super.handleMessage(msg); 246d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 247d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 248d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan } 249d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan 250d428549b58b2df5015bff81d79747265ee8be536Kevin Crossan} 251