UsbDeviceManager.java revision 166b05e0ce913711d27ce1a116b3f1fd906822e4
1/* 2 * Copyright (C) 2011 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 an 14 * limitations under the License. 15 */ 16 17package com.android.server.usb; 18 19import android.app.PendingIntent; 20import android.app.Notification; 21import android.app.NotificationManager; 22import android.content.BroadcastReceiver; 23import android.content.ComponentName; 24import android.content.ContentResolver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.content.pm.PackageManager; 29import android.content.res.Resources; 30import android.database.ContentObserver; 31import android.hardware.usb.UsbAccessory; 32import android.hardware.usb.UsbManager; 33import android.net.Uri; 34import android.os.Binder; 35import android.os.Bundle; 36import android.os.FileUtils; 37import android.os.Handler; 38import android.os.HandlerThread; 39import android.os.Looper; 40import android.os.Message; 41import android.os.Parcelable; 42import android.os.ParcelFileDescriptor; 43import android.os.Process; 44import android.os.storage.StorageManager; 45import android.os.storage.StorageVolume; 46import android.os.SystemClock; 47import android.os.SystemProperties; 48import android.os.UEventObserver; 49import android.provider.Settings; 50import android.util.Pair; 51import android.util.Slog; 52 53import java.io.File; 54import java.io.FileDescriptor; 55import java.io.FileNotFoundException; 56import java.io.IOException; 57import java.io.PrintWriter; 58import java.util.ArrayList; 59import java.util.LinkedList; 60import java.util.List; 61import java.util.HashMap; 62import java.util.Map; 63import java.util.Scanner; 64 65/** 66 * UsbDeviceManager manages USB state in device mode. 67 */ 68public class UsbDeviceManager { 69 70 private static final String TAG = UsbDeviceManager.class.getSimpleName(); 71 private static final boolean DEBUG = false; 72 73 private static final String USB_STATE_MATCH = 74 "DEVPATH=/devices/virtual/android_usb/android0"; 75 private static final String ACCESSORY_START_MATCH = 76 "DEVPATH=/devices/virtual/misc/usb_accessory"; 77 private static final String FUNCTIONS_PATH = 78 "/sys/class/android_usb/android0/functions"; 79 private static final String STATE_PATH = 80 "/sys/class/android_usb/android0/state"; 81 private static final String MASS_STORAGE_FILE_PATH = 82 "/sys/class/android_usb/android0/f_mass_storage/lun/file"; 83 private static final String RNDIS_ETH_ADDR_PATH = 84 "/sys/class/android_usb/android0/f_rndis/ethaddr"; 85 private static final String AUDIO_SOURCE_PCM_PATH = 86 "/sys/class/android_usb/android0/f_audio_source/pcm"; 87 88 private static final int MSG_UPDATE_STATE = 0; 89 private static final int MSG_ENABLE_ADB = 1; 90 private static final int MSG_SET_CURRENT_FUNCTIONS = 2; 91 private static final int MSG_SYSTEM_READY = 3; 92 private static final int MSG_BOOT_COMPLETED = 4; 93 94 private static final int AUDIO_MODE_NONE = 0; 95 private static final int AUDIO_MODE_SOURCE = 1; 96 97 // Delay for debouncing USB disconnects. 98 // We often get rapid connect/disconnect events when enabling USB functions, 99 // which need debouncing. 100 private static final int UPDATE_DELAY = 1000; 101 102 private static final String BOOT_MODE_PROPERTY = "ro.bootmode"; 103 104 private UsbHandler mHandler; 105 private boolean mBootCompleted; 106 107 private final Context mContext; 108 private final ContentResolver mContentResolver; 109 private final UsbSettingsManager mSettingsManager; 110 private NotificationManager mNotificationManager; 111 private final boolean mHasUsbAccessory; 112 private boolean mUseUsbNotification; 113 private boolean mAdbEnabled; 114 private boolean mAudioSourceEnabled; 115 private Map<String, List<Pair<String, String>>> mOemModeMap; 116 private String[] mAccessoryStrings; 117 118 private class AdbSettingsObserver extends ContentObserver { 119 public AdbSettingsObserver() { 120 super(null); 121 } 122 @Override 123 public void onChange(boolean selfChange) { 124 boolean enable = (Settings.Secure.getInt(mContentResolver, 125 Settings.Secure.ADB_ENABLED, 0) > 0); 126 mHandler.sendMessage(MSG_ENABLE_ADB, enable); 127 } 128 } 129 130 /* 131 * Listens for uevent messages from the kernel to monitor the USB state 132 */ 133 private final UEventObserver mUEventObserver = new UEventObserver() { 134 @Override 135 public void onUEvent(UEventObserver.UEvent event) { 136 if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString()); 137 138 String state = event.get("USB_STATE"); 139 String accessory = event.get("ACCESSORY"); 140 if (state != null) { 141 mHandler.updateState(state); 142 } else if ("START".equals(accessory)) { 143 if (DEBUG) Slog.d(TAG, "got accessory start"); 144 startAccessoryMode(); 145 } 146 } 147 }; 148 149 public UsbDeviceManager(Context context, UsbSettingsManager settingsManager) { 150 mContext = context; 151 mContentResolver = context.getContentResolver(); 152 mSettingsManager = settingsManager; 153 PackageManager pm = mContext.getPackageManager(); 154 mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY); 155 initRndisAddress(); 156 157 readOemUsbOverrideConfig(); 158 159 // create a thread for our Handler 160 HandlerThread thread = new HandlerThread("UsbDeviceManager", 161 Process.THREAD_PRIORITY_BACKGROUND); 162 thread.start(); 163 mHandler = new UsbHandler(thread.getLooper()); 164 165 if (nativeIsStartRequested()) { 166 if (DEBUG) Slog.d(TAG, "accessory attached at boot"); 167 startAccessoryMode(); 168 } 169 } 170 171 public void systemReady() { 172 if (DEBUG) Slog.d(TAG, "systemReady"); 173 174 mNotificationManager = (NotificationManager) 175 mContext.getSystemService(Context.NOTIFICATION_SERVICE); 176 177 // We do not show the USB notification if the primary volume supports mass storage. 178 // The legacy mass storage UI will be used instead. 179 boolean massStorageSupported = false; 180 StorageManager storageManager = (StorageManager) 181 mContext.getSystemService(Context.STORAGE_SERVICE); 182 StorageVolume[] volumes = storageManager.getVolumeList(); 183 if (volumes.length > 0) { 184 massStorageSupported = volumes[0].allowMassStorage(); 185 } 186 mUseUsbNotification = !massStorageSupported; 187 188 // make sure the ADB_ENABLED setting value matches the current state 189 Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED, mAdbEnabled ? 1 : 0); 190 191 mHandler.sendEmptyMessage(MSG_SYSTEM_READY); 192 } 193 194 private void startAccessoryMode() { 195 mAccessoryStrings = nativeGetAccessoryStrings(); 196 boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE); 197 // don't start accessory mode if our mandatory strings have not been set 198 boolean enableAccessory = (mAccessoryStrings != null && 199 mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null && 200 mAccessoryStrings[UsbAccessory.MODEL_STRING] != null); 201 String functions = null; 202 203 if (enableAccessory && enableAudio) { 204 functions = UsbManager.USB_FUNCTION_ACCESSORY + "," 205 + UsbManager.USB_FUNCTION_AUDIO_SOURCE; 206 } else if (enableAccessory) { 207 functions = UsbManager.USB_FUNCTION_ACCESSORY; 208 } else if (enableAudio) { 209 functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE; 210 } 211 212 if (functions != null) { 213 setCurrentFunctions(functions, false); 214 } 215 } 216 217 private static void initRndisAddress() { 218 // configure RNDIS ethernet address based on our serial number using the same algorithm 219 // we had been previously using in kernel board files 220 final int ETH_ALEN = 6; 221 int address[] = new int[ETH_ALEN]; 222 // first byte is 0x02 to signify a locally administered address 223 address[0] = 0x02; 224 225 String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF"); 226 int serialLength = serial.length(); 227 // XOR the USB serial across the remaining 5 bytes 228 for (int i = 0; i < serialLength; i++) { 229 address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i); 230 } 231 String addrString = String.format("%02X:%02X:%02X:%02X:%02X:%02X", 232 address[0], address[1], address[2], address[3], address[4], address[5]); 233 try { 234 FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString); 235 } catch (IOException e) { 236 Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH); 237 } 238 } 239 240 private static String addFunction(String functions, String function) { 241 if ("none".equals(functions)) { 242 return function; 243 } 244 if (!containsFunction(functions, function)) { 245 if (functions.length() > 0) { 246 functions += ","; 247 } 248 functions += function; 249 } 250 return functions; 251 } 252 253 private static String removeFunction(String functions, String function) { 254 String[] split = functions.split(","); 255 for (int i = 0; i < split.length; i++) { 256 if (function.equals(split[i])) { 257 split[i] = null; 258 } 259 } 260 if (split.length == 1 && split[0] == null) { 261 return "none"; 262 } 263 StringBuilder builder = new StringBuilder(); 264 for (int i = 0; i < split.length; i++) { 265 String s = split[i]; 266 if (s != null) { 267 if (builder.length() > 0) { 268 builder.append(","); 269 } 270 builder.append(s); 271 } 272 } 273 return builder.toString(); 274 } 275 276 private static boolean containsFunction(String functions, String function) { 277 int index = functions.indexOf(function); 278 if (index < 0) return false; 279 if (index > 0 && functions.charAt(index - 1) != ',') return false; 280 int charAfter = index + function.length(); 281 if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false; 282 return true; 283 } 284 285 private final class UsbHandler extends Handler { 286 287 // current USB state 288 private boolean mConnected; 289 private boolean mConfigured; 290 private String mCurrentFunctions; 291 private String mDefaultFunctions; 292 private UsbAccessory mCurrentAccessory; 293 private int mUsbNotificationId; 294 private boolean mAdbNotificationShown; 295 296 private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() { 297 public void onReceive(Context context, Intent intent) { 298 if (DEBUG) Slog.d(TAG, "boot completed"); 299 mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED); 300 } 301 }; 302 303 public UsbHandler(Looper looper) { 304 super(looper); 305 try { 306 // persist.sys.usb.config should never be unset. But if it is, set it to "adb" 307 // so we have a chance of debugging what happened. 308 mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb"); 309 310 // Check if USB mode needs to be overridden depending on OEM specific bootmode. 311 mDefaultFunctions = processOemUsbOverride(mDefaultFunctions); 312 313 // sanity check the sys.usb.config system property 314 // this may be necessary if we crashed while switching USB configurations 315 String config = SystemProperties.get("sys.usb.config", "none"); 316 if (!config.equals(mDefaultFunctions)) { 317 Slog.w(TAG, "resetting config to persistent property: " + mDefaultFunctions); 318 SystemProperties.set("sys.usb.config", mDefaultFunctions); 319 } 320 321 mCurrentFunctions = mDefaultFunctions; 322 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); 323 updateState(state); 324 mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB); 325 mAudioSourceEnabled = containsFunction(mCurrentFunctions, 326 UsbManager.USB_FUNCTION_AUDIO_SOURCE); 327 328 // Upgrade step for previous versions that used persist.service.adb.enable 329 String value = SystemProperties.get("persist.service.adb.enable", ""); 330 if (value.length() > 0) { 331 char enable = value.charAt(0); 332 if (enable == '1') { 333 setAdbEnabled(true); 334 } else if (enable == '0') { 335 setAdbEnabled(false); 336 } 337 SystemProperties.set("persist.service.adb.enable", ""); 338 } 339 340 // register observer to listen for settings changes 341 mContentResolver.registerContentObserver( 342 Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED), 343 false, new AdbSettingsObserver()); 344 345 // Watch for USB configuration changes 346 mUEventObserver.startObserving(USB_STATE_MATCH); 347 mUEventObserver.startObserving(ACCESSORY_START_MATCH); 348 349 mContext.registerReceiver(mBootCompletedReceiver, 350 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 351 } catch (Exception e) { 352 Slog.e(TAG, "Error initializing UsbHandler", e); 353 } 354 } 355 356 public void sendMessage(int what, boolean arg) { 357 removeMessages(what); 358 Message m = Message.obtain(this, what); 359 m.arg1 = (arg ? 1 : 0); 360 sendMessage(m); 361 } 362 363 public void sendMessage(int what, Object arg) { 364 removeMessages(what); 365 Message m = Message.obtain(this, what); 366 m.obj = arg; 367 sendMessage(m); 368 } 369 370 public void sendMessage(int what, Object arg0, boolean arg1) { 371 removeMessages(what); 372 Message m = Message.obtain(this, what); 373 m.obj = arg0; 374 m.arg1 = (arg1 ? 1 : 0); 375 sendMessage(m); 376 } 377 378 public void updateState(String state) { 379 int connected, configured; 380 381 if ("DISCONNECTED".equals(state)) { 382 connected = 0; 383 configured = 0; 384 } else if ("CONNECTED".equals(state)) { 385 connected = 1; 386 configured = 0; 387 } else if ("CONFIGURED".equals(state)) { 388 connected = 1; 389 configured = 1; 390 } else { 391 Slog.e(TAG, "unknown state " + state); 392 return; 393 } 394 removeMessages(MSG_UPDATE_STATE); 395 Message msg = Message.obtain(this, MSG_UPDATE_STATE); 396 msg.arg1 = connected; 397 msg.arg2 = configured; 398 // debounce disconnects to avoid problems bringing up USB tethering 399 sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0); 400 } 401 402 private boolean waitForState(String state) { 403 // wait for the transition to complete. 404 // give up after 1 second. 405 for (int i = 0; i < 20; i++) { 406 // State transition is done when sys.usb.state is set to the new configuration 407 if (state.equals(SystemProperties.get("sys.usb.state"))) return true; 408 SystemClock.sleep(50); 409 } 410 Slog.e(TAG, "waitForState(" + state + ") FAILED"); 411 return false; 412 } 413 414 private boolean setUsbConfig(String config) { 415 if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")"); 416 // set the new configuration 417 SystemProperties.set("sys.usb.config", config); 418 return waitForState(config); 419 } 420 421 private void setAdbEnabled(boolean enable) { 422 if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable); 423 if (enable != mAdbEnabled) { 424 mAdbEnabled = enable; 425 // Due to the persist.sys.usb.config property trigger, changing adb state requires 426 // switching to default function 427 setEnabledFunctions(mDefaultFunctions, true); 428 updateAdbNotification(); 429 } 430 } 431 432 private void setEnabledFunctions(String functions, boolean makeDefault) { 433 434 // Do not update persystent.sys.usb.config if the device is booted up 435 // with OEM specific mode. 436 if (functions != null && makeDefault && !needsOemUsbOverride()) { 437 438 if (mAdbEnabled) { 439 functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB); 440 } else { 441 functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB); 442 } 443 if (!mDefaultFunctions.equals(functions)) { 444 if (!setUsbConfig("none")) { 445 Slog.e(TAG, "Failed to disable USB"); 446 // revert to previous configuration if we fail 447 setUsbConfig(mCurrentFunctions); 448 return; 449 } 450 // setting this property will also change the current USB state 451 // via a property trigger 452 SystemProperties.set("persist.sys.usb.config", functions); 453 if (waitForState(functions)) { 454 mCurrentFunctions = functions; 455 mDefaultFunctions = functions; 456 } else { 457 Slog.e(TAG, "Failed to switch persistent USB config to " + functions); 458 // revert to previous configuration if we fail 459 SystemProperties.set("persist.sys.usb.config", mDefaultFunctions); 460 } 461 } 462 } else { 463 if (functions == null) { 464 functions = mDefaultFunctions; 465 } 466 467 // Override with bootmode specific usb mode if needed 468 functions = processOemUsbOverride(functions); 469 470 if (mAdbEnabled) { 471 functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB); 472 } else { 473 functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB); 474 } 475 if (!mCurrentFunctions.equals(functions)) { 476 if (!setUsbConfig("none")) { 477 Slog.e(TAG, "Failed to disable USB"); 478 // revert to previous configuration if we fail 479 setUsbConfig(mCurrentFunctions); 480 return; 481 } 482 if (setUsbConfig(functions)) { 483 mCurrentFunctions = functions; 484 } else { 485 Slog.e(TAG, "Failed to switch USB config to " + functions); 486 // revert to previous configuration if we fail 487 setUsbConfig(mCurrentFunctions); 488 } 489 } 490 } 491 } 492 493 private void updateCurrentAccessory() { 494 if (!mHasUsbAccessory) return; 495 496 if (mConfigured) { 497 if (mAccessoryStrings != null) { 498 mCurrentAccessory = new UsbAccessory(mAccessoryStrings); 499 Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); 500 // defer accessoryAttached if system is not ready 501 if (mBootCompleted) { 502 mSettingsManager.accessoryAttached(mCurrentAccessory); 503 } // else handle in mBootCompletedReceiver 504 } else { 505 Slog.e(TAG, "nativeGetAccessoryStrings failed"); 506 } 507 } else if (!mConnected) { 508 // make sure accessory mode is off 509 // and restore default functions 510 Slog.d(TAG, "exited USB accessory mode"); 511 setEnabledFunctions(mDefaultFunctions, false); 512 513 if (mCurrentAccessory != null) { 514 if (mBootCompleted) { 515 mSettingsManager.accessoryDetached(mCurrentAccessory); 516 } 517 mCurrentAccessory = null; 518 mAccessoryStrings = null; 519 } 520 } 521 } 522 523 private void updateUsbState() { 524 // send a sticky broadcast containing current USB state 525 Intent intent = new Intent(UsbManager.ACTION_USB_STATE); 526 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 527 intent.putExtra(UsbManager.USB_CONNECTED, mConnected); 528 intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured); 529 530 if (mCurrentFunctions != null) { 531 String[] functions = mCurrentFunctions.split(","); 532 for (int i = 0; i < functions.length; i++) { 533 intent.putExtra(functions[i], true); 534 } 535 } 536 537 mContext.sendStickyBroadcast(intent); 538 } 539 540 private void updateAudioSourceFunction(boolean enabled) { 541 // send a sticky broadcast containing current USB state 542 Intent intent = new Intent(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG); 543 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 544 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 545 intent.putExtra("state", (enabled ? 1 : 0)); 546 if (enabled) { 547 try { 548 Scanner scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH)); 549 int card = scanner.nextInt(); 550 int device = scanner.nextInt(); 551 intent.putExtra("card", card); 552 intent.putExtra("device", device); 553 } catch (FileNotFoundException e) { 554 Slog.e(TAG, "could not open audio source PCM file", e); 555 } 556 } 557 558 mContext.sendStickyBroadcast(intent); 559 mAudioSourceEnabled = enabled; 560 } 561 562 @Override 563 public void handleMessage(Message msg) { 564 switch (msg.what) { 565 case MSG_UPDATE_STATE: 566 mConnected = (msg.arg1 == 1); 567 mConfigured = (msg.arg2 == 1); 568 updateUsbNotification(); 569 updateAdbNotification(); 570 if (containsFunction(mCurrentFunctions, 571 UsbManager.USB_FUNCTION_ACCESSORY)) { 572 updateCurrentAccessory(); 573 } 574 575 if (!mConnected) { 576 // restore defaults when USB is disconnected 577 setEnabledFunctions(mDefaultFunctions, false); 578 } 579 if (mBootCompleted) { 580 updateUsbState(); 581 boolean audioSourceEnabled = containsFunction(mCurrentFunctions, 582 UsbManager.USB_FUNCTION_AUDIO_SOURCE); 583 if (audioSourceEnabled != mAudioSourceEnabled) { 584 updateAudioSourceFunction(audioSourceEnabled); 585 } 586 } 587 break; 588 case MSG_ENABLE_ADB: 589 setAdbEnabled(msg.arg1 == 1); 590 break; 591 case MSG_SET_CURRENT_FUNCTIONS: 592 String functions = (String)msg.obj; 593 boolean makeDefault = (msg.arg1 == 1); 594 setEnabledFunctions(functions, makeDefault); 595 break; 596 case MSG_SYSTEM_READY: 597 updateUsbNotification(); 598 updateAdbNotification(); 599 updateUsbState(); 600 break; 601 case MSG_BOOT_COMPLETED: 602 mBootCompleted = true; 603 if (mCurrentAccessory != null) { 604 mSettingsManager.accessoryAttached(mCurrentAccessory); 605 } 606 updateAudioSourceFunction(mAudioSourceEnabled); 607 break; 608 } 609 } 610 611 public UsbAccessory getCurrentAccessory() { 612 return mCurrentAccessory; 613 } 614 615 private void updateUsbNotification() { 616 if (mNotificationManager == null || !mUseUsbNotification) return; 617 int id = 0; 618 Resources r = mContext.getResources(); 619 if (mConnected) { 620 if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) { 621 id = com.android.internal.R.string.usb_mtp_notification_title; 622 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) { 623 id = com.android.internal.R.string.usb_ptp_notification_title; 624 } else if (containsFunction(mCurrentFunctions, 625 UsbManager.USB_FUNCTION_MASS_STORAGE)) { 626 id = com.android.internal.R.string.usb_cd_installer_notification_title; 627 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) { 628 id = com.android.internal.R.string.usb_accessory_notification_title; 629 } else { 630 // There is a different notification for USB tethering so we don't need one here 631 if (!containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) { 632 Slog.e(TAG, "No known USB function in updateUsbNotification"); 633 } 634 } 635 } 636 if (id != mUsbNotificationId) { 637 // clear notification if title needs changing 638 if (mUsbNotificationId != 0) { 639 mNotificationManager.cancel(mUsbNotificationId); 640 mUsbNotificationId = 0; 641 } 642 if (id != 0) { 643 CharSequence message = r.getText( 644 com.android.internal.R.string.usb_notification_message); 645 CharSequence title = r.getText(id); 646 647 Notification notification = new Notification(); 648 notification.icon = com.android.internal.R.drawable.stat_sys_data_usb; 649 notification.when = 0; 650 notification.flags = Notification.FLAG_ONGOING_EVENT; 651 notification.tickerText = title; 652 notification.defaults = 0; // please be quiet 653 notification.sound = null; 654 notification.vibrate = null; 655 notification.priority = Notification.PRIORITY_MIN; 656 657 Intent intent = Intent.makeRestartActivityTask( 658 new ComponentName("com.android.settings", 659 "com.android.settings.UsbSettings")); 660 PendingIntent pi = PendingIntent.getActivity(mContext, 0, 661 intent, 0); 662 notification.setLatestEventInfo(mContext, title, message, pi); 663 mNotificationManager.notify(id, notification); 664 mUsbNotificationId = id; 665 } 666 } 667 } 668 669 private void updateAdbNotification() { 670 if (mNotificationManager == null) return; 671 final int id = com.android.internal.R.string.adb_active_notification_title; 672 if (mAdbEnabled && mConnected) { 673 if ("0".equals(SystemProperties.get("persist.adb.notify"))) return; 674 675 if (!mAdbNotificationShown) { 676 Resources r = mContext.getResources(); 677 CharSequence title = r.getText(id); 678 CharSequence message = r.getText( 679 com.android.internal.R.string.adb_active_notification_message); 680 681 Notification notification = new Notification(); 682 notification.icon = com.android.internal.R.drawable.stat_sys_adb; 683 notification.when = 0; 684 notification.flags = Notification.FLAG_ONGOING_EVENT; 685 notification.tickerText = title; 686 notification.defaults = 0; // please be quiet 687 notification.sound = null; 688 notification.vibrate = null; 689 notification.priority = Notification.PRIORITY_MIN; 690 691 Intent intent = Intent.makeRestartActivityTask( 692 new ComponentName("com.android.settings", 693 "com.android.settings.DevelopmentSettings")); 694 PendingIntent pi = PendingIntent.getActivity(mContext, 0, 695 intent, 0); 696 notification.setLatestEventInfo(mContext, title, message, pi); 697 mAdbNotificationShown = true; 698 mNotificationManager.notify(id, notification); 699 } 700 } else if (mAdbNotificationShown) { 701 mAdbNotificationShown = false; 702 mNotificationManager.cancel(id); 703 } 704 } 705 706 public void dump(FileDescriptor fd, PrintWriter pw) { 707 pw.println(" USB Device State:"); 708 pw.println(" Current Functions: " + mCurrentFunctions); 709 pw.println(" Default Functions: " + mDefaultFunctions); 710 pw.println(" mConnected: " + mConnected); 711 pw.println(" mConfigured: " + mConfigured); 712 pw.println(" mCurrentAccessory: " + mCurrentAccessory); 713 try { 714 pw.println(" Kernel state: " 715 + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim()); 716 pw.println(" Kernel function list: " 717 + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim()); 718 pw.println(" Mass storage backing file: " 719 + FileUtils.readTextFile(new File(MASS_STORAGE_FILE_PATH), 0, null).trim()); 720 } catch (IOException e) { 721 pw.println("IOException: " + e); 722 } 723 } 724 } 725 726 /* returns the currently attached USB accessory */ 727 public UsbAccessory getCurrentAccessory() { 728 return mHandler.getCurrentAccessory(); 729 } 730 731 /* opens the currently attached USB accessory */ 732 public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { 733 UsbAccessory currentAccessory = mHandler.getCurrentAccessory(); 734 if (currentAccessory == null) { 735 throw new IllegalArgumentException("no accessory attached"); 736 } 737 if (!currentAccessory.equals(accessory)) { 738 String error = accessory.toString() 739 + " does not match current accessory " 740 + currentAccessory; 741 throw new IllegalArgumentException(error); 742 } 743 mSettingsManager.checkPermission(accessory); 744 return nativeOpenAccessory(); 745 } 746 747 public void setCurrentFunctions(String functions, boolean makeDefault) { 748 if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ") default: " + makeDefault); 749 mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, makeDefault); 750 } 751 752 public void setMassStorageBackingFile(String path) { 753 if (path == null) path = ""; 754 try { 755 FileUtils.stringToFile(MASS_STORAGE_FILE_PATH, path); 756 } catch (IOException e) { 757 Slog.e(TAG, "failed to write to " + MASS_STORAGE_FILE_PATH); 758 } 759 } 760 761 private void readOemUsbOverrideConfig() { 762 String[] configList = mContext.getResources().getStringArray( 763 com.android.internal.R.array.config_oemUsbModeOverride); 764 765 if (configList != null) { 766 for (String config: configList) { 767 String[] items = config.split(":"); 768 if (items.length == 3) { 769 if (mOemModeMap == null) { 770 mOemModeMap = new HashMap<String, List<Pair<String, String>>>(); 771 } 772 List overrideList = mOemModeMap.get(items[0]); 773 if (overrideList == null) { 774 overrideList = new LinkedList<Pair<String, String>>(); 775 mOemModeMap.put(items[0], overrideList); 776 } 777 overrideList.add(new Pair<String, String>(items[1], items[2])); 778 } 779 } 780 } 781 } 782 783 private boolean needsOemUsbOverride() { 784 if (mOemModeMap == null) return false; 785 786 String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); 787 return (mOemModeMap.get(bootMode) != null) ? true : false; 788 } 789 790 private String processOemUsbOverride(String usbFunctions) { 791 if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions; 792 793 String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); 794 795 List<Pair<String, String>> overrides = mOemModeMap.get(bootMode); 796 if (overrides != null) { 797 for (Pair<String, String> pair: overrides) { 798 if (pair.first.equals(usbFunctions)) { 799 Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second); 800 return pair.second; 801 } 802 } 803 } 804 // return passed in functions as is. 805 return usbFunctions; 806 } 807 808 public void dump(FileDescriptor fd, PrintWriter pw) { 809 if (mHandler != null) { 810 mHandler.dump(fd, pw); 811 } 812 } 813 814 private native String[] nativeGetAccessoryStrings(); 815 private native ParcelFileDescriptor nativeOpenAccessory(); 816 private native boolean nativeIsStartRequested(); 817 private native int nativeGetAudioMode(); 818} 819