@@ -40,15 +40,33 @@ class UsbService {
4040 private static final String TAG = UsbService .class .getSimpleName ();
4141 private static final boolean LOG = false ;
4242
43- private static final String USB_CONFIGURATION_MATCH = "DEVPATH=/devices/virtual/switch/usb_configuration" ;
44- private static final String USB_FUNCTIONS_MATCH = "DEVPATH=/devices/virtual/usb_composite/" ;
45- private static final String USB_CONFIGURATION_PATH = "/sys/class/switch/usb_configuration/state" ;
46- private static final String USB_COMPOSITE_CLASS_PATH = "/sys/class/usb_composite" ;
43+ private static final String USB_CONNECTED_MATCH =
44+ "DEVPATH=/devices/virtual/switch/usb_connected" ;
45+ private static final String USB_CONFIGURATION_MATCH =
46+ "DEVPATH=/devices/virtual/switch/usb_configuration" ;
47+ private static final String USB_FUNCTIONS_MATCH =
48+ "DEVPATH=/devices/virtual/usb_composite/" ;
49+ private static final String USB_CONNECTED_PATH =
50+ "/sys/class/switch/usb_connected/state" ;
51+ private static final String USB_CONFIGURATION_PATH =
52+ "/sys/class/switch/usb_configuration/state" ;
53+ private static final String USB_COMPOSITE_CLASS_PATH =
54+ "/sys/class/usb_composite" ;
4755
4856 private static final int MSG_UPDATE = 0 ;
4957
50- private int mUsbConfig = 0 ;
51- private int mPreviousUsbConfig = 0 ;
58+ // Delay for debouncing USB disconnects.
59+ // We often get rapid connect/disconnect events when enabling USB functions,
60+ // which need debouncing.
61+ private static final int UPDATE_DELAY = 1000 ;
62+
63+ // current connected and configuration state
64+ private int mConnected ;
65+ private int mConfiguration ;
66+
67+ // last broadcasted connected and configuration state
68+ private int mLastConnected = -1 ;
69+ private int mLastConfiguration = -1 ;
5270
5371 // lists of enabled and disabled USB functions
5472 private final ArrayList <String > mEnabledFunctions = new ArrayList <String >();
@@ -58,8 +76,6 @@ class UsbService {
5876
5977 private final Context mContext ;
6078
61- private PowerManagerService mPowerManager ;
62-
6379 private final UEventObserver mUEventObserver = new UEventObserver () {
6480 @ Override
6581 public void onUEvent (UEventObserver .UEvent event ) {
@@ -68,16 +84,23 @@ public void onUEvent(UEventObserver.UEvent event) {
6884 }
6985
7086 synchronized (this ) {
71- String switchState = event .get ("SWITCH_STATE" );
72- if (switchState != null ) {
87+ String name = event .get ("SWITCH_NAME" );
88+ String state = event .get ("SWITCH_STATE" );
89+ if (name != null && state != null ) {
7390 try {
74- int newConfig = Integer .parseInt (switchState );
75- if (newConfig != mUsbConfig ) {
76- mPreviousUsbConfig = mUsbConfig ;
77- mUsbConfig = newConfig ;
91+ int intState = Integer .parseInt (state );
92+ if ("usb_connected" .equals (name )) {
93+ mConnected = intState ;
94+ // trigger an Intent broadcast
95+ if (mSystemReady ) {
96+ // debounce disconnects
97+ update (mConnected == 0 );
98+ }
99+ } else if ("usb_configuration" .equals (name )) {
100+ mConfiguration = intState ;
78101 // trigger an Intent broadcast
79102 if (mSystemReady ) {
80- update ();
103+ update (mConnected == 0 );
81104 }
82105 }
83106 } catch (NumberFormatException e ) {
@@ -111,6 +134,7 @@ public UsbService(Context context) {
111134 mContext = context ;
112135 init (); // set initial status
113136
137+ mUEventObserver .startObserving (USB_CONNECTED_MATCH );
114138 mUEventObserver .startObserving (USB_CONFIGURATION_MATCH );
115139 mUEventObserver .startObserving (USB_FUNCTIONS_MATCH );
116140 }
@@ -119,10 +143,15 @@ private final void init() {
119143 char [] buffer = new char [1024 ];
120144
121145 try {
122- FileReader file = new FileReader (USB_CONFIGURATION_PATH );
146+ FileReader file = new FileReader (USB_CONNECTED_PATH );
123147 int len = file .read (buffer , 0 , 1024 );
124- mPreviousUsbConfig = mUsbConfig = Integer .valueOf ((new String (buffer , 0 , len )).trim ());
148+ file .close ();
149+ mConnected = Integer .valueOf ((new String (buffer , 0 , len )).trim ());
125150
151+ file = new FileReader (USB_CONFIGURATION_PATH );
152+ len = file .read (buffer , 0 , 1024 );
153+ file .close ();
154+ mConfiguration = Integer .valueOf ((new String (buffer , 0 , len )).trim ());
126155 } catch (FileNotFoundException e ) {
127156 Slog .w (TAG , "This kernel does not have USB configuration switch support" );
128157 } catch (Exception e ) {
@@ -135,6 +164,7 @@ private final void init() {
135164 File file = new File (files [i ], "enable" );
136165 FileReader reader = new FileReader (file );
137166 int len = reader .read (buffer , 0 , 1024 );
167+ reader .close ();
138168 int value = Integer .valueOf ((new String (buffer , 0 , len )).trim ());
139169 String functionName = files [i ].getName ();
140170 if (value == 1 ) {
@@ -152,13 +182,14 @@ private final void init() {
152182
153183 void systemReady () {
154184 synchronized (this ) {
155- update ();
185+ update (false );
156186 mSystemReady = true ;
157187 }
158188 }
159189
160- private final void update () {
161- mHandler .sendEmptyMessage (MSG_UPDATE );
190+ private final void update (boolean delayed ) {
191+ mHandler .removeMessages (MSG_UPDATE );
192+ mHandler .sendEmptyMessageDelayed (MSG_UPDATE , delayed ? UPDATE_DELAY : 0 );
162193 }
163194
164195 private final Handler mHandler = new Handler () {
@@ -177,31 +208,26 @@ public void handleMessage(Message msg) {
177208 switch (msg .what ) {
178209 case MSG_UPDATE :
179210 synchronized (this ) {
180- final ContentResolver cr = mContext . getContentResolver ();
211+ if ( mConnected != mLastConnected || mConfiguration != mLastConfiguration ) {
181212
182- if (Settings .Secure .getInt (cr ,
183- Settings .Secure .DEVICE_PROVISIONED , 0 ) == 0 ) {
184- Slog .i (TAG , "Device not provisioned, skipping USB broadcast" );
185- return ;
186- }
187- // Send an Intent containing connected/disconnected state
188- // and the enabled/disabled state of all USB functions
189- Intent intent ;
190- boolean usbConnected = (mUsbConfig != 0 );
191- if (usbConnected ) {
192- intent = new Intent (UsbManager .ACTION_USB_CONNECTED );
213+ final ContentResolver cr = mContext .getContentResolver ();
214+ if (Settings .Secure .getInt (cr ,
215+ Settings .Secure .DEVICE_PROVISIONED , 0 ) == 0 ) {
216+ Slog .i (TAG , "Device not provisioned, skipping USB broadcast" );
217+ return ;
218+ }
219+
220+ mLastConnected = mConnected ;
221+ mLastConfiguration = mConfiguration ;
222+
223+ // send a sticky broadcast containing current USB state
224+ Intent intent = new Intent (UsbManager .ACTION_USB_STATE );
225+ intent .addFlags (Intent .FLAG_RECEIVER_REPLACE_PENDING );
226+ intent .putExtra (UsbManager .USB_CONNECTED , mConnected != 0 );
227+ intent .putExtra (UsbManager .USB_CONFIGURATION , mConfiguration );
193228 addEnabledFunctions (intent );
194- } else {
195- intent = new Intent (UsbManager .ACTION_USB_DISCONNECTED );
229+ mContext .sendStickyBroadcast (intent );
196230 }
197- mContext .sendBroadcast (intent );
198-
199- // send a sticky broadcast for clients interested in both connect and disconnect
200- intent = new Intent (UsbManager .ACTION_USB_STATE );
201- intent .addFlags (Intent .FLAG_RECEIVER_REPLACE_PENDING );
202- intent .putExtra (UsbManager .USB_CONNECTED , usbConnected );
203- addEnabledFunctions (intent );
204- mContext .sendStickyBroadcast (intent );
205231 }
206232 break ;
207233 }
0 commit comments