1badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park/*
2badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park * Copyright (C) 2016 The Android Open Source Project
3badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park *
4badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park * Licensed under the Apache License, Version 2.0 (the "License");
5badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park * you may not use this file except in compliance with the License.
6badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park * You may obtain a copy of the License at
7badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park *
8badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park *      http://www.apache.org/licenses/LICENSE-2.0
9badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park *
10badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park * Unless required by applicable law or agreed to in writing, software
11badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park * distributed under the License is distributed on an "AS IS" BASIS,
12badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park * See the License for the specific language governing permissions and
14badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park * limitations under the License.
15badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park */
16badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkpackage com.android.hardware.usb.externalmanagementtest;
17badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
18badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport android.content.BroadcastReceiver;
19badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport android.content.Context;
20badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport android.content.Intent;
21badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport android.content.IntentFilter;
22badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport android.hardware.usb.UsbDevice;
23badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport android.hardware.usb.UsbDeviceConnection;
24badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport android.hardware.usb.UsbManager;
25badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport android.os.Handler;
26badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport android.os.HandlerThread;
27badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport android.os.Looper;
28badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport android.os.Message;
29badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport android.util.Log;
30badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
31badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport java.util.LinkedList;
32badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
33badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkimport dalvik.system.CloseGuard;
34badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
35badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Parkpublic class UsbDeviceStateController {
36badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
37badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    public interface UsbDeviceStateListener {
38badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        void onDeviceResetComplete(UsbDevice device);
39badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        void onAoapStartComplete(UsbDevice devie);
40badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
41badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
42badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private static final String TAG = UsbDeviceStateController.class.getSimpleName();
43badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
44badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private static final int MAX_USB_STATE_CHANGE_WAIT = 5;
45badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private static final long USB_STATE_CHANGE_WAIT_TIMEOUT_MS = 500;
46badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
47badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private final Context mContext;
48badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private final UsbDeviceStateListener mListener;
49badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private final UsbManager mUsbManager;
50badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private final HandlerThread mHandlerThread;
51badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private final UsbStateHandler mHandler;
52badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private final UsbDeviceBroadcastReceiver mUsbStateBroadcastReceiver;
53badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private final CloseGuard mCloseGuard = CloseGuard.get();
54badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
55badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private final Object mUsbConnectionChangeWait = new Object();
56badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private final LinkedList<UsbDevice> mDevicesRemoved = new LinkedList<>();
57badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private final LinkedList<UsbDevice> mDevicesAdded = new LinkedList<>();
58badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private boolean mShouldQuit = false;
59badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
60badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    public UsbDeviceStateController(Context context, UsbDeviceStateListener listener,
61badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            UsbManager usbManager) {
62badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mContext = context;
63badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mListener = listener;
64badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mUsbManager = usbManager;
65badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mHandlerThread = new HandlerThread(TAG);
66badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mHandlerThread.start();
67badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mCloseGuard.open("release");
68badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mHandler = new UsbStateHandler(mHandlerThread.getLooper());
69badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mUsbStateBroadcastReceiver = new UsbDeviceBroadcastReceiver();
70badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
71badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
72badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    public void init() {
73badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        IntentFilter filter = new IntentFilter();
74badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
75badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
76badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mContext.registerReceiver(mUsbStateBroadcastReceiver, filter);
77badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
78badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
79badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    public void release() {
80badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mCloseGuard.close();
81badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mContext.unregisterReceiver(mUsbStateBroadcastReceiver);
82badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        synchronized (mUsbConnectionChangeWait) {
83badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            mShouldQuit = true;
84badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            mUsbConnectionChangeWait.notifyAll();
85badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
86badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mHandlerThread.quit();
87badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
88badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
89badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    @Override
90badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    protected void finalize() throws Throwable {
91badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        try {
92492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath            if (mCloseGuard != null) {
93492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath                mCloseGuard.warnIfOpen();
94492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath            }
95492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath
96badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            release();
97badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        } finally {
98badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            super.finalize();
99badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
100badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
101badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
102badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    public void startDeviceReset(UsbDevice device) {
103badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mHandler.requestDeviceReset(device);
104badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
105badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
106badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    public void startAoap(AoapSwitchRequest request) {
107badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mHandler.requestAoap(request);
108badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
109badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
110badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private void doHandleDeviceReset(UsbDevice device) {
111badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        boolean isInAoap = AoapInterface.isDeviceInAoapMode(device);
112badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        UsbDevice completedDevice = null;
113badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        if (isInAoap) {
114badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            completedDevice = resetUsbDeviceAndConfirmModeChange(device);
115badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        } else {
116badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            UsbDeviceConnection conn = openConnection(device);
117badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            if (conn == null) {
118badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                throw new RuntimeException("cannot open conneciton for device: " + device);
119badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            } else {
120badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                try {
121badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    if (!conn.resetDevice()) {
122badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                        throw new RuntimeException("resetDevice failed for devie: " + device);
123badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    } else {
124badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                        completedDevice = device;
125badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    }
126badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                } finally {
127badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    conn.close();
128badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                }
129badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            }
130badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
131badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mListener.onDeviceResetComplete(completedDevice);
132badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
133badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
134badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private void doHandleAoapStart(AoapSwitchRequest request) {
135badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        UsbDevice device = request.device;
136badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        boolean isInAoap = AoapInterface.isDeviceInAoapMode(device);
137badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        if (isInAoap) {
138badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            device = resetUsbDeviceAndConfirmModeChange(device);
139badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            if (device == null) {
140badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                mListener.onAoapStartComplete(null);
141badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                return;
142badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            }
143badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
144badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        UsbDeviceConnection connection = openConnection(device);
145badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MANUFACTURER,
146badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                request.manufacturer);
147badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MODEL,
148badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                request.model);
149badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_DESCRIPTION,
150badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                request.description);
151badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_VERSION,
152badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                request.version);
153badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_URI, request.uri);
154badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_SERIAL, request.serial);
155badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        AoapInterface.sendAoapStart(connection);
156badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        device = resetUsbDeviceAndConfirmModeChange(device);
157badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        if (device == null) {
158badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            mListener.onAoapStartComplete(null);
159badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
160badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        if (!AoapInterface.isDeviceInAoapMode(device)) {
161badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            Log.w(TAG, "Device not in AOAP mode after switching: " + device);
162badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            mListener.onAoapStartComplete(device);
163badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
164badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mListener.onAoapStartComplete(device);
165badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
166badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
167badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private UsbDevice resetUsbDeviceAndConfirmModeChange(UsbDevice device) {
168badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        int retry = 0;
169badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        boolean removalDetected = false;
170badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        while (retry < MAX_USB_STATE_CHANGE_WAIT) {
171badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            UsbDeviceConnection connNow = openConnection(device);
172badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            if (connNow == null) {
173badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                removalDetected = true;
174badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                break;
175badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            }
176badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            connNow.resetDevice();
177badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            connNow.close();
178badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            synchronized (mUsbConnectionChangeWait) {
179badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                try {
180badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    mUsbConnectionChangeWait.wait(USB_STATE_CHANGE_WAIT_TIMEOUT_MS);
181badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                } catch (InterruptedException e) {
182badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    break;
183badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                }
184badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                if (mShouldQuit) {
185badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    return null;
186badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                }
187badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                if (isDeviceRemovedLocked(device)) {
188badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    removalDetected = true;
189badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    break;
190badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                }
191badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            }
192badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            retry++;
193badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
194badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        if (!removalDetected) {
195badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            Log.w(TAG, "resetDevice failed for device, device still in the same mode: " + device);
196badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            return null;
197badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
198badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        retry = 0;
199badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        UsbDevice newlyAttached = null;
200badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        while (retry < MAX_USB_STATE_CHANGE_WAIT) {
201badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            synchronized (mUsbConnectionChangeWait) {
202badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                try {
203badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    mUsbConnectionChangeWait.wait(USB_STATE_CHANGE_WAIT_TIMEOUT_MS);
204badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                } catch (InterruptedException e) {
205badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    break;
206badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                }
207badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                if (mShouldQuit) {
208badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    return null;
209badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                }
210badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                newlyAttached = checkDeviceAttachedLocked(device);
211badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            }
212badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            if (newlyAttached != null) {
213badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                break;
214badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            }
215badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            retry++;
216badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
217badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        if (newlyAttached == null) {
218badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            Log.w(TAG, "resetDevice failed for device, device disconnected: " + device);
219badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            return null;
220badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
221badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        return newlyAttached;
222badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
223badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
224badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private boolean isDeviceRemovedLocked(UsbDevice device) {
225badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        for (UsbDevice removed : mDevicesRemoved) {
226badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            if (UsbUtil.isDevicesMatching(device, removed)) {
227badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                mDevicesRemoved.clear();
228badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                return true;
229badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            }
230badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
231badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mDevicesRemoved.clear();
232badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        return false;
233badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
234badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
235badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private UsbDevice checkDeviceAttachedLocked(UsbDevice device) {
236badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        for (UsbDevice attached : mDevicesAdded) {
237badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            if (UsbUtil.isTheSameDevice(device, attached)) {
238badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                mDevicesAdded.clear();
239badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                return attached;
240badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            }
241badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
242badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mDevicesAdded.clear();
243badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        return null;
244badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
245badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
246badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    public UsbDeviceConnection openConnection(UsbDevice device) {
247badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        mUsbManager.grantPermission(device);
248badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        return mUsbManager.openDevice(device);
249badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
250badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
251badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private void handleUsbDeviceAttached(UsbDevice device) {
252badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        synchronized (mUsbConnectionChangeWait) {
253badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            mDevicesAdded.add(device);
254badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            mUsbConnectionChangeWait.notifyAll();
255badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
256badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
257badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
258badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private void handleUsbDeviceDetached(UsbDevice device) {
259badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        synchronized (mUsbConnectionChangeWait) {
260badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            mDevicesRemoved.add(device);
261badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            mUsbConnectionChangeWait.notifyAll();
262badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
263badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
264badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
265badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private class UsbStateHandler extends Handler {
266badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        private final int MSG_RESET_DEVICE = 1;
267badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        private final int MSG_AOAP = 2;
268badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
269badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        private UsbStateHandler(Looper looper) {
270badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            super(looper);
271badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
272badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
273badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        private void requestDeviceReset(UsbDevice device) {
274badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            Message msg = obtainMessage(MSG_RESET_DEVICE, device);
275badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            sendMessage(msg);
276badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
277badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
278badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        private void requestAoap(AoapSwitchRequest request) {
279badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            Message msg = obtainMessage(MSG_AOAP, request);
280badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            sendMessage(msg);
281badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
282badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
283badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        @Override
284badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        public void handleMessage(Message msg) {
285badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            switch (msg.what) {
286badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                case MSG_RESET_DEVICE:
287badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    doHandleDeviceReset((UsbDevice) msg.obj);
288badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    break;
289badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                case MSG_AOAP:
290badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    doHandleAoapStart((AoapSwitchRequest) msg.obj);
291badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                    break;
292badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            }
293badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
294badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
295badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
296badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    private class UsbDeviceBroadcastReceiver extends BroadcastReceiver {
297badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        @Override
298badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        public void onReceive(Context context, Intent intent) {
299badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) {
300badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
301badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                handleUsbDeviceDetached(device);
302badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
303badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
304badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                handleUsbDeviceAttached(device);
305badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            }
306badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
307badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
308badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
309badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    public static class AoapSwitchRequest {
310badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        public final UsbDevice device;
311badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        public final String manufacturer;
312badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        public final String model;
313badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        public final String description;
314badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        public final String version;
315badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        public final String uri;
316badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        public final String serial;
317badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park
318badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        public AoapSwitchRequest(UsbDevice device, String manufacturer, String model,
319badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park                String description, String version, String uri, String serial) {
320badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            this.device = device;
321badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            this.manufacturer = manufacturer;
322badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            this.model = model;
323badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            this.description = description;
324badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            this.version = version;
325badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            this.uri = uri;
326badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park            this.serial = serial;
327badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park        }
328badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park    }
329badbbae6fa2846415778b2a152a0758acbf0eb74Keun-young Park}
330