blob: 87aa8cce166ab217c89c65777dce9a067e72db5c [file] [log] [blame]
Mike Lockwood46d0adf2011-05-26 10:27:39 -04001/*
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
Mike Lockwood541c9942011-06-12 19:35:45 -040019import android.app.Notification;
20import android.app.NotificationManager;
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -070021import android.app.PendingIntent;
Mike Lockwoodd462ecf2011-07-21 13:55:16 -070022import android.content.BroadcastReceiver;
Mike Lockwood541c9942011-06-12 19:35:45 -040023import android.content.ComponentName;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040024import android.content.ContentResolver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.pm.PackageManager;
Mike Lockwood541c9942011-06-12 19:35:45 -040029import android.content.res.Resources;
30import android.database.ContentObserver;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040031import android.hardware.usb.UsbAccessory;
32import android.hardware.usb.UsbManager;
Mike Lockwood02e45692011-06-14 15:43:51 -040033import android.os.FileUtils;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040034import android.os.Handler;
Mike Lockwood02e45692011-06-14 15:43:51 -040035import android.os.HandlerThread;
36import android.os.Looper;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040037import android.os.Message;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040038import android.os.ParcelFileDescriptor;
Mike Lockwood02e45692011-06-14 15:43:51 -040039import android.os.Process;
RoboErikdab20722012-03-07 17:53:36 -080040import android.os.SystemClock;
Mike Lockwood541c9942011-06-12 19:35:45 -040041import android.os.SystemProperties;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040042import android.os.UEventObserver;
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -070043import android.os.UserHandle;
44import android.os.storage.StorageManager;
45import android.os.storage.StorageVolume;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040046import android.provider.Settings;
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -060047import android.util.Pair;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040048import android.util.Slog;
49
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080050import com.android.internal.annotations.GuardedBy;
51
Mike Lockwood46d0adf2011-05-26 10:27:39 -040052import java.io.File;
53import java.io.FileDescriptor;
54import java.io.FileNotFoundException;
Mike Lockwood02e45692011-06-14 15:43:51 -040055import java.io.IOException;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040056import java.io.PrintWriter;
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -070057import java.util.HashMap;
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -060058import java.util.LinkedList;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040059import java.util.List;
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -060060import java.util.Map;
Mike Lockwood9d5a4be2012-04-06 09:41:32 -070061import java.util.Scanner;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040062
63/**
64 * UsbDeviceManager manages USB state in device mode.
65 */
66public class UsbDeviceManager {
Mike Lockwood02e45692011-06-14 15:43:51 -040067
Mike Lockwood46d0adf2011-05-26 10:27:39 -040068 private static final String TAG = UsbDeviceManager.class.getSimpleName();
Mike Lockwoodfdc0c292011-07-01 11:17:43 -040069 private static final boolean DEBUG = false;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040070
Mike Lockwood02e45692011-06-14 15:43:51 -040071 private static final String USB_STATE_MATCH =
72 "DEVPATH=/devices/virtual/android_usb/android0";
73 private static final String ACCESSORY_START_MATCH =
74 "DEVPATH=/devices/virtual/misc/usb_accessory";
75 private static final String FUNCTIONS_PATH =
76 "/sys/class/android_usb/android0/functions";
77 private static final String STATE_PATH =
78 "/sys/class/android_usb/android0/state";
79 private static final String MASS_STORAGE_FILE_PATH =
Mike Lockwood629b1492011-07-06 12:47:21 -040080 "/sys/class/android_usb/android0/f_mass_storage/lun/file";
81 private static final String RNDIS_ETH_ADDR_PATH =
82 "/sys/class/android_usb/android0/f_rndis/ethaddr";
Mike Lockwood9d5a4be2012-04-06 09:41:32 -070083 private static final String AUDIO_SOURCE_PCM_PATH =
84 "/sys/class/android_usb/android0/f_audio_source/pcm";
Mike Lockwood46d0adf2011-05-26 10:27:39 -040085
86 private static final int MSG_UPDATE_STATE = 0;
Mike Lockwood02e45692011-06-14 15:43:51 -040087 private static final int MSG_ENABLE_ADB = 1;
Mike Lockwood166b05e2012-04-24 10:45:18 -070088 private static final int MSG_SET_CURRENT_FUNCTIONS = 2;
Mike Lockwoodf59717d2011-06-22 15:19:33 -040089 private static final int MSG_SYSTEM_READY = 3;
Mike Lockwoodd462ecf2011-07-21 13:55:16 -070090 private static final int MSG_BOOT_COMPLETED = 4;
Jeff Sharkey27bd34d2012-09-16 12:49:00 -070091 private static final int MSG_USER_SWITCHED = 5;
Mike Lockwood46d0adf2011-05-26 10:27:39 -040092
Mike Lockwood166b05e2012-04-24 10:45:18 -070093 private static final int AUDIO_MODE_NONE = 0;
94 private static final int AUDIO_MODE_SOURCE = 1;
95
Mike Lockwood46d0adf2011-05-26 10:27:39 -040096 // Delay for debouncing USB disconnects.
97 // We often get rapid connect/disconnect events when enabling USB functions,
98 // which need debouncing.
99 private static final int UPDATE_DELAY = 1000;
100
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -0600101 private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
102
Mike Lockwood02e45692011-06-14 15:43:51 -0400103 private UsbHandler mHandler;
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700104 private boolean mBootCompleted;
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400105
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700106 private final Object mLock = new Object();
107
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400108 private final Context mContext;
Mike Lockwood02e45692011-06-14 15:43:51 -0400109 private final ContentResolver mContentResolver;
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800110 @GuardedBy("mLock")
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700111 private UsbSettingsManager mCurrentSettings;
Mike Lockwood541c9942011-06-12 19:35:45 -0400112 private NotificationManager mNotificationManager;
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400113 private final boolean mHasUsbAccessory;
Mike Lockwood5787a2d2011-06-17 12:21:39 -0400114 private boolean mUseUsbNotification;
Mike Lockwood541c9942011-06-12 19:35:45 -0400115 private boolean mAdbEnabled;
Mike Lockwood9d5a4be2012-04-06 09:41:32 -0700116 private boolean mAudioSourceEnabled;
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -0600117 private Map<String, List<Pair<String, String>>> mOemModeMap;
Mike Lockwood166b05e2012-04-24 10:45:18 -0700118 private String[] mAccessoryStrings;
Benoit Goby4e68bd42012-04-25 18:06:00 -0700119 private UsbDebuggingManager mDebuggingManager;
Mike Lockwood541c9942011-06-12 19:35:45 -0400120
121 private class AdbSettingsObserver extends ContentObserver {
122 public AdbSettingsObserver() {
123 super(null);
124 }
125 @Override
126 public void onChange(boolean selfChange) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700127 boolean enable = (Settings.Global.getInt(mContentResolver,
128 Settings.Global.ADB_ENABLED, 0) > 0);
Mike Lockwood02e45692011-06-14 15:43:51 -0400129 mHandler.sendMessage(MSG_ENABLE_ADB, enable);
Mike Lockwood541c9942011-06-12 19:35:45 -0400130 }
131 }
132
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400133 /*
134 * Listens for uevent messages from the kernel to monitor the USB state
135 */
136 private final UEventObserver mUEventObserver = new UEventObserver() {
137 @Override
138 public void onUEvent(UEventObserver.UEvent event) {
Mike Lockwoodfdc0c292011-07-01 11:17:43 -0400139 if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400140
Mike Lockwood02e45692011-06-14 15:43:51 -0400141 String state = event.get("USB_STATE");
142 String accessory = event.get("ACCESSORY");
143 if (state != null) {
144 mHandler.updateState(state);
145 } else if ("START".equals(accessory)) {
Mike Lockwoodfdc0c292011-07-01 11:17:43 -0400146 if (DEBUG) Slog.d(TAG, "got accessory start");
Mike Lockwood166b05e2012-04-24 10:45:18 -0700147 startAccessoryMode();
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400148 }
149 }
150 };
151
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700152 public UsbDeviceManager(Context context) {
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400153 mContext = context;
Mike Lockwood541c9942011-06-12 19:35:45 -0400154 mContentResolver = context.getContentResolver();
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400155 PackageManager pm = mContext.getPackageManager();
156 mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
Mike Lockwood629b1492011-07-06 12:47:21 -0400157 initRndisAddress();
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400158
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -0600159 readOemUsbOverrideConfig();
160
Mike Lockwood02e45692011-06-14 15:43:51 -0400161 // create a thread for our Handler
162 HandlerThread thread = new HandlerThread("UsbDeviceManager",
Mike Lockwood3fd13eb2011-07-13 09:23:45 -0400163 Process.THREAD_PRIORITY_BACKGROUND);
Mike Lockwood02e45692011-06-14 15:43:51 -0400164 thread.start();
Mike Lockwood3fd13eb2011-07-13 09:23:45 -0400165 mHandler = new UsbHandler(thread.getLooper());
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700166
167 if (nativeIsStartRequested()) {
168 if (DEBUG) Slog.d(TAG, "accessory attached at boot");
Mike Lockwood166b05e2012-04-24 10:45:18 -0700169 startAccessoryMode();
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700170 }
Benoit Goby4e68bd42012-04-25 18:06:00 -0700171
Benoit Goby78a96872013-01-25 16:58:13 -0800172 boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false);
173 boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt"));
174 if (secureAdbEnabled && !dataEncrypted) {
Benoit Goby4e68bd42012-04-25 18:06:00 -0700175 mDebuggingManager = new UsbDebuggingManager(context);
176 }
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400177 }
178
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700179 public void setCurrentSettings(UsbSettingsManager settings) {
180 synchronized (mLock) {
181 mCurrentSettings = settings;
182 }
183 }
184
185 private UsbSettingsManager getCurrentSettings() {
186 synchronized (mLock) {
187 return mCurrentSettings;
188 }
189 }
190
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400191 public void systemReady() {
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700192 if (DEBUG) Slog.d(TAG, "systemReady");
Mike Lockwood541c9942011-06-12 19:35:45 -0400193
Mike Lockwood02e45692011-06-14 15:43:51 -0400194 mNotificationManager = (NotificationManager)
195 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
196
Mike Lockwood5787a2d2011-06-17 12:21:39 -0400197 // We do not show the USB notification if the primary volume supports mass storage.
198 // The legacy mass storage UI will be used instead.
199 boolean massStorageSupported = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700200 final StorageManager storageManager = StorageManager.from(mContext);
201 final StorageVolume primary = storageManager.getPrimaryVolume();
202 massStorageSupported = primary != null && primary.allowMassStorage();
Mike Lockwood5787a2d2011-06-17 12:21:39 -0400203 mUseUsbNotification = !massStorageSupported;
204
Mike Lockwood02e45692011-06-14 15:43:51 -0400205 // make sure the ADB_ENABLED setting value matches the current state
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700206 Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0);
Mike Lockwood02e45692011-06-14 15:43:51 -0400207
208 mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
209 }
210
Mike Lockwood166b05e2012-04-24 10:45:18 -0700211 private void startAccessoryMode() {
212 mAccessoryStrings = nativeGetAccessoryStrings();
213 boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
214 // don't start accessory mode if our mandatory strings have not been set
215 boolean enableAccessory = (mAccessoryStrings != null &&
216 mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null &&
217 mAccessoryStrings[UsbAccessory.MODEL_STRING] != null);
218 String functions = null;
219
220 if (enableAccessory && enableAudio) {
221 functions = UsbManager.USB_FUNCTION_ACCESSORY + ","
222 + UsbManager.USB_FUNCTION_AUDIO_SOURCE;
223 } else if (enableAccessory) {
224 functions = UsbManager.USB_FUNCTION_ACCESSORY;
225 } else if (enableAudio) {
226 functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE;
227 }
228
229 if (functions != null) {
230 setCurrentFunctions(functions, false);
231 }
232 }
233
Mike Lockwood629b1492011-07-06 12:47:21 -0400234 private static void initRndisAddress() {
235 // configure RNDIS ethernet address based on our serial number using the same algorithm
236 // we had been previously using in kernel board files
237 final int ETH_ALEN = 6;
238 int address[] = new int[ETH_ALEN];
239 // first byte is 0x02 to signify a locally administered address
240 address[0] = 0x02;
241
242 String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF");
243 int serialLength = serial.length();
244 // XOR the USB serial across the remaining 5 bytes
245 for (int i = 0; i < serialLength; i++) {
246 address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i);
247 }
248 String addrString = String.format("%02X:%02X:%02X:%02X:%02X:%02X",
249 address[0], address[1], address[2], address[3], address[4], address[5]);
250 try {
251 FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString);
252 } catch (IOException e) {
253 Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH);
254 }
255 }
256
Mike Lockwood02e45692011-06-14 15:43:51 -0400257 private static String addFunction(String functions, String function) {
RoboErikdab20722012-03-07 17:53:36 -0800258 if ("none".equals(functions)) {
259 return function;
260 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400261 if (!containsFunction(functions, function)) {
262 if (functions.length() > 0) {
263 functions += ",";
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400264 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400265 functions += function;
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400266 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400267 return functions;
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400268 }
269
Mike Lockwood02e45692011-06-14 15:43:51 -0400270 private static String removeFunction(String functions, String function) {
271 String[] split = functions.split(",");
272 for (int i = 0; i < split.length; i++) {
273 if (function.equals(split[i])) {
274 split[i] = null;
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400275 }
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400276 }
RoboErikdab20722012-03-07 17:53:36 -0800277 if (split.length == 1 && split[0] == null) {
278 return "none";
279 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400280 StringBuilder builder = new StringBuilder();
281 for (int i = 0; i < split.length; i++) {
282 String s = split[i];
283 if (s != null) {
284 if (builder.length() > 0) {
285 builder.append(",");
286 }
287 builder.append(s);
288 }
289 }
290 return builder.toString();
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400291 }
292
Mike Lockwood02e45692011-06-14 15:43:51 -0400293 private static boolean containsFunction(String functions, String function) {
294 int index = functions.indexOf(function);
295 if (index < 0) return false;
296 if (index > 0 && functions.charAt(index - 1) != ',') return false;
297 int charAfter = index + function.length();
298 if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
299 return true;
300 }
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400301
Mike Lockwood02e45692011-06-14 15:43:51 -0400302 private final class UsbHandler extends Handler {
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400303
Mike Lockwood02e45692011-06-14 15:43:51 -0400304 // current USB state
305 private boolean mConnected;
306 private boolean mConfigured;
307 private String mCurrentFunctions;
308 private String mDefaultFunctions;
309 private UsbAccessory mCurrentAccessory;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400310 private int mUsbNotificationId;
311 private boolean mAdbNotificationShown;
Jeff Sharkey27bd34d2012-09-16 12:49:00 -0700312 private int mCurrentUser = UserHandle.USER_NULL;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400313
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700314 private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
Jeff Sharkey27bd34d2012-09-16 12:49:00 -0700315 @Override
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700316 public void onReceive(Context context, Intent intent) {
317 if (DEBUG) Slog.d(TAG, "boot completed");
318 mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
319 }
320 };
321
Jeff Sharkey27bd34d2012-09-16 12:49:00 -0700322 private final BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() {
323 @Override
324 public void onReceive(Context context, Intent intent) {
325 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
326 mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget();
327 }
328 };
329
Mike Lockwood3fd13eb2011-07-13 09:23:45 -0400330 public UsbHandler(Looper looper) {
331 super(looper);
Mike Lockwood02e45692011-06-14 15:43:51 -0400332 try {
Mike Lockwoodc264afeb52011-07-10 11:48:18 -0400333 // persist.sys.usb.config should never be unset. But if it is, set it to "adb"
334 // so we have a chance of debugging what happened.
335 mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -0600336
337 // Check if USB mode needs to be overridden depending on OEM specific bootmode.
338 mDefaultFunctions = processOemUsbOverride(mDefaultFunctions);
339
Mike Lockwoodde296f62011-07-01 14:05:25 -0400340 // sanity check the sys.usb.config system property
341 // this may be necessary if we crashed while switching USB configurations
342 String config = SystemProperties.get("sys.usb.config", "none");
Mike Lockwoodc264afeb52011-07-10 11:48:18 -0400343 if (!config.equals(mDefaultFunctions)) {
344 Slog.w(TAG, "resetting config to persistent property: " + mDefaultFunctions);
345 SystemProperties.set("sys.usb.config", mDefaultFunctions);
Mike Lockwoodde296f62011-07-01 14:05:25 -0400346 }
347
Mike Lockwoodc264afeb52011-07-10 11:48:18 -0400348 mCurrentFunctions = mDefaultFunctions;
Mike Lockwood02e45692011-06-14 15:43:51 -0400349 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
350 updateState(state);
Mike Lockwood02e45692011-06-14 15:43:51 -0400351 mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400352
Mike Lockwood02e45692011-06-14 15:43:51 -0400353 // Upgrade step for previous versions that used persist.service.adb.enable
354 String value = SystemProperties.get("persist.service.adb.enable", "");
355 if (value.length() > 0) {
356 char enable = value.charAt(0);
357 if (enable == '1') {
358 setAdbEnabled(true);
359 } else if (enable == '0') {
360 setAdbEnabled(false);
361 }
362 SystemProperties.set("persist.service.adb.enable", "");
363 }
364
365 // register observer to listen for settings changes
366 mContentResolver.registerContentObserver(
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700367 Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
Mike Lockwood02e45692011-06-14 15:43:51 -0400368 false, new AdbSettingsObserver());
369
370 // Watch for USB configuration changes
371 mUEventObserver.startObserving(USB_STATE_MATCH);
372 mUEventObserver.startObserving(ACCESSORY_START_MATCH);
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700373
Jeff Sharkey27bd34d2012-09-16 12:49:00 -0700374 mContext.registerReceiver(
375 mBootCompletedReceiver, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
376 mContext.registerReceiver(
377 mUserSwitchedReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
Mike Lockwood02e45692011-06-14 15:43:51 -0400378 } catch (Exception e) {
379 Slog.e(TAG, "Error initializing UsbHandler", e);
380 }
381 }
382
383 public void sendMessage(int what, boolean arg) {
384 removeMessages(what);
385 Message m = Message.obtain(this, what);
386 m.arg1 = (arg ? 1 : 0);
387 sendMessage(m);
388 }
389
390 public void sendMessage(int what, Object arg) {
391 removeMessages(what);
392 Message m = Message.obtain(this, what);
393 m.obj = arg;
394 sendMessage(m);
395 }
396
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400397 public void sendMessage(int what, Object arg0, boolean arg1) {
398 removeMessages(what);
399 Message m = Message.obtain(this, what);
400 m.obj = arg0;
401 m.arg1 = (arg1 ? 1 : 0);
402 sendMessage(m);
403 }
404
Mike Lockwood02e45692011-06-14 15:43:51 -0400405 public void updateState(String state) {
406 int connected, configured;
407
408 if ("DISCONNECTED".equals(state)) {
409 connected = 0;
410 configured = 0;
411 } else if ("CONNECTED".equals(state)) {
412 connected = 1;
413 configured = 0;
414 } else if ("CONFIGURED".equals(state)) {
415 connected = 1;
416 configured = 1;
417 } else {
418 Slog.e(TAG, "unknown state " + state);
419 return;
420 }
421 removeMessages(MSG_UPDATE_STATE);
422 Message msg = Message.obtain(this, MSG_UPDATE_STATE);
423 msg.arg1 = connected;
424 msg.arg2 = configured;
425 // debounce disconnects to avoid problems bringing up USB tethering
426 sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
427 }
428
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400429 private boolean waitForState(String state) {
Mike Lockwood02e45692011-06-14 15:43:51 -0400430 // wait for the transition to complete.
431 // give up after 1 second.
432 for (int i = 0; i < 20; i++) {
Mike Lockwood68736cb2011-07-29 11:32:28 -0400433 // State transition is done when sys.usb.state is set to the new configuration
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400434 if (state.equals(SystemProperties.get("sys.usb.state"))) return true;
RoboErikdab20722012-03-07 17:53:36 -0800435 SystemClock.sleep(50);
Mike Lockwood02e45692011-06-14 15:43:51 -0400436 }
Mike Lockwoodfdc0c292011-07-01 11:17:43 -0400437 Slog.e(TAG, "waitForState(" + state + ") FAILED");
Mike Lockwood02e45692011-06-14 15:43:51 -0400438 return false;
439 }
440
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400441 private boolean setUsbConfig(String config) {
Mike Lockwoodfdc0c292011-07-01 11:17:43 -0400442 if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400443 // set the new configuration
444 SystemProperties.set("sys.usb.config", config);
445 return waitForState(config);
446 }
447
Mike Lockwood02e45692011-06-14 15:43:51 -0400448 private void setAdbEnabled(boolean enable) {
Mike Lockwoodde296f62011-07-01 14:05:25 -0400449 if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
Mike Lockwood02e45692011-06-14 15:43:51 -0400450 if (enable != mAdbEnabled) {
451 mAdbEnabled = enable;
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400452 // Due to the persist.sys.usb.config property trigger, changing adb state requires
453 // switching to default function
Mike Lockwood1984e792011-08-03 17:10:43 -0400454 setEnabledFunctions(mDefaultFunctions, true);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400455 updateAdbNotification();
Mike Lockwood02e45692011-06-14 15:43:51 -0400456 }
Benoit Goby4e68bd42012-04-25 18:06:00 -0700457 if (mDebuggingManager != null) {
458 mDebuggingManager.setAdbEnabled(mAdbEnabled);
459 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400460 }
461
Mike Lockwood68736cb2011-07-29 11:32:28 -0400462 private void setEnabledFunctions(String functions, boolean makeDefault) {
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -0600463
464 // Do not update persystent.sys.usb.config if the device is booted up
465 // with OEM specific mode.
466 if (functions != null && makeDefault && !needsOemUsbOverride()) {
467
Mike Lockwood8b4d36e2011-08-02 18:16:26 -0400468 if (mAdbEnabled) {
469 functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
470 } else {
471 functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
472 }
Mike Lockwood68736cb2011-07-29 11:32:28 -0400473 if (!mDefaultFunctions.equals(functions)) {
474 if (!setUsbConfig("none")) {
475 Slog.e(TAG, "Failed to disable USB");
476 // revert to previous configuration if we fail
477 setUsbConfig(mCurrentFunctions);
478 return;
479 }
480 // setting this property will also change the current USB state
481 // via a property trigger
482 SystemProperties.set("persist.sys.usb.config", functions);
483 if (waitForState(functions)) {
484 mCurrentFunctions = functions;
485 mDefaultFunctions = functions;
486 } else {
487 Slog.e(TAG, "Failed to switch persistent USB config to " + functions);
488 // revert to previous configuration if we fail
489 SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
490 }
491 }
492 } else {
493 if (functions == null) {
494 functions = mDefaultFunctions;
495 }
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -0600496
497 // Override with bootmode specific usb mode if needed
498 functions = processOemUsbOverride(functions);
499
Mike Lockwood8b4d36e2011-08-02 18:16:26 -0400500 if (mAdbEnabled) {
501 functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
502 } else {
503 functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
504 }
Mike Lockwood68736cb2011-07-29 11:32:28 -0400505 if (!mCurrentFunctions.equals(functions)) {
506 if (!setUsbConfig("none")) {
507 Slog.e(TAG, "Failed to disable USB");
508 // revert to previous configuration if we fail
509 setUsbConfig(mCurrentFunctions);
510 return;
511 }
512 if (setUsbConfig(functions)) {
513 mCurrentFunctions = functions;
514 } else {
515 Slog.e(TAG, "Failed to switch USB config to " + functions);
516 // revert to previous configuration if we fail
517 setUsbConfig(mCurrentFunctions);
518 }
519 }
520 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400521 }
522
523 private void updateCurrentAccessory() {
524 if (!mHasUsbAccessory) return;
525
526 if (mConfigured) {
Mike Lockwood166b05e2012-04-24 10:45:18 -0700527 if (mAccessoryStrings != null) {
528 mCurrentAccessory = new UsbAccessory(mAccessoryStrings);
Mike Lockwoodfdc0c292011-07-01 11:17:43 -0400529 Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
Mike Lockwood02e45692011-06-14 15:43:51 -0400530 // defer accessoryAttached if system is not ready
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700531 if (mBootCompleted) {
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700532 getCurrentSettings().accessoryAttached(mCurrentAccessory);
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700533 } // else handle in mBootCompletedReceiver
Mike Lockwood02e45692011-06-14 15:43:51 -0400534 } else {
Mike Lockwoodfdc0c292011-07-01 11:17:43 -0400535 Slog.e(TAG, "nativeGetAccessoryStrings failed");
Mike Lockwood02e45692011-06-14 15:43:51 -0400536 }
537 } else if (!mConnected) {
538 // make sure accessory mode is off
539 // and restore default functions
Mike Lockwoodfdc0c292011-07-01 11:17:43 -0400540 Slog.d(TAG, "exited USB accessory mode");
Mike Lockwood68736cb2011-07-29 11:32:28 -0400541 setEnabledFunctions(mDefaultFunctions, false);
Mike Lockwood02e45692011-06-14 15:43:51 -0400542
543 if (mCurrentAccessory != null) {
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700544 if (mBootCompleted) {
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700545 getCurrentSettings().accessoryDetached(mCurrentAccessory);
Mike Lockwood02e45692011-06-14 15:43:51 -0400546 }
547 mCurrentAccessory = null;
Mike Lockwood166b05e2012-04-24 10:45:18 -0700548 mAccessoryStrings = null;
Mike Lockwood02e45692011-06-14 15:43:51 -0400549 }
550 }
551 }
552
553 private void updateUsbState() {
554 // send a sticky broadcast containing current USB state
555 Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
556 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
557 intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
558 intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
559
560 if (mCurrentFunctions != null) {
561 String[] functions = mCurrentFunctions.split(",");
562 for (int i = 0; i < functions.length; i++) {
563 intent.putExtra(functions[i], true);
564 }
565 }
566
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700567 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Mike Lockwood02e45692011-06-14 15:43:51 -0400568 }
569
Mike Lockwoodbf910462012-05-09 16:19:20 -0700570 private void updateAudioSourceFunction() {
571 boolean enabled = containsFunction(mCurrentFunctions,
572 UsbManager.USB_FUNCTION_AUDIO_SOURCE);
573 if (enabled != mAudioSourceEnabled) {
574 // send a sticky broadcast containing current USB state
575 Intent intent = new Intent(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
576 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
577 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
578 intent.putExtra("state", (enabled ? 1 : 0));
579 if (enabled) {
580 try {
581 Scanner scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
582 int card = scanner.nextInt();
583 int device = scanner.nextInt();
584 intent.putExtra("card", card);
585 intent.putExtra("device", device);
586 } catch (FileNotFoundException e) {
587 Slog.e(TAG, "could not open audio source PCM file", e);
588 }
Mike Lockwood9d5a4be2012-04-06 09:41:32 -0700589 }
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700590 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Mike Lockwoodbf910462012-05-09 16:19:20 -0700591 mAudioSourceEnabled = enabled;
Mike Lockwood9d5a4be2012-04-06 09:41:32 -0700592 }
Mike Lockwood9d5a4be2012-04-06 09:41:32 -0700593 }
594
Mike Lockwood02e45692011-06-14 15:43:51 -0400595 @Override
596 public void handleMessage(Message msg) {
Mike Lockwood02e45692011-06-14 15:43:51 -0400597 switch (msg.what) {
598 case MSG_UPDATE_STATE:
599 mConnected = (msg.arg1 == 1);
600 mConfigured = (msg.arg2 == 1);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400601 updateUsbNotification();
602 updateAdbNotification();
Mike Lockwood02e45692011-06-14 15:43:51 -0400603 if (containsFunction(mCurrentFunctions,
604 UsbManager.USB_FUNCTION_ACCESSORY)) {
605 updateCurrentAccessory();
606 }
607
608 if (!mConnected) {
609 // restore defaults when USB is disconnected
Mike Lockwood68736cb2011-07-29 11:32:28 -0400610 setEnabledFunctions(mDefaultFunctions, false);
Mike Lockwood02e45692011-06-14 15:43:51 -0400611 }
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700612 if (mBootCompleted) {
Mike Lockwood02e45692011-06-14 15:43:51 -0400613 updateUsbState();
Mike Lockwoodbf910462012-05-09 16:19:20 -0700614 updateAudioSourceFunction();
Mike Lockwood02e45692011-06-14 15:43:51 -0400615 }
616 break;
617 case MSG_ENABLE_ADB:
618 setAdbEnabled(msg.arg1 == 1);
619 break;
Mike Lockwood166b05e2012-04-24 10:45:18 -0700620 case MSG_SET_CURRENT_FUNCTIONS:
621 String functions = (String)msg.obj;
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400622 boolean makeDefault = (msg.arg1 == 1);
Mike Lockwood166b05e2012-04-24 10:45:18 -0700623 setEnabledFunctions(functions, makeDefault);
Mike Lockwood02e45692011-06-14 15:43:51 -0400624 break;
625 case MSG_SYSTEM_READY:
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400626 updateUsbNotification();
627 updateAdbNotification();
Mike Lockwood02e45692011-06-14 15:43:51 -0400628 updateUsbState();
Mike Lockwoodbf910462012-05-09 16:19:20 -0700629 updateAudioSourceFunction();
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700630 break;
631 case MSG_BOOT_COMPLETED:
632 mBootCompleted = true;
633 if (mCurrentAccessory != null) {
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700634 getCurrentSettings().accessoryAttached(mCurrentAccessory);
Mike Lockwood02e45692011-06-14 15:43:51 -0400635 }
Benoit Goby4e68bd42012-04-25 18:06:00 -0700636 if (mDebuggingManager != null) {
637 mDebuggingManager.setAdbEnabled(mAdbEnabled);
638 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400639 break;
Jeff Sharkey27bd34d2012-09-16 12:49:00 -0700640 case MSG_USER_SWITCHED: {
641 final boolean mtpActive =
642 containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)
643 || containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP);
644 if (mtpActive && mCurrentUser != UserHandle.USER_NULL) {
645 Slog.v(TAG, "Current user switched; resetting USB host stack for MTP");
646 setUsbConfig("none");
647 setUsbConfig(mCurrentFunctions);
648 }
649 mCurrentUser = msg.arg1;
650 break;
651 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400652 }
653 }
654
655 public UsbAccessory getCurrentAccessory() {
656 return mCurrentAccessory;
657 }
658
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400659 private void updateUsbNotification() {
660 if (mNotificationManager == null || !mUseUsbNotification) return;
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700661 int id = 0;
Mike Lockwooda5010432011-07-27 09:50:06 -0400662 Resources r = mContext.getResources();
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400663 if (mConnected) {
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400664 if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) {
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700665 id = com.android.internal.R.string.usb_mtp_notification_title;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400666 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) {
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700667 id = com.android.internal.R.string.usb_ptp_notification_title;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400668 } else if (containsFunction(mCurrentFunctions,
669 UsbManager.USB_FUNCTION_MASS_STORAGE)) {
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700670 id = com.android.internal.R.string.usb_cd_installer_notification_title;
Mike Lockwood6e680de2011-07-21 15:36:09 -0700671 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) {
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700672 id = com.android.internal.R.string.usb_accessory_notification_title;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400673 } else {
Mike Lockwooda5010432011-07-27 09:50:06 -0400674 // There is a different notification for USB tethering so we don't need one here
Dianne Hackborn7ff30112012-11-08 11:12:09 -0800675 //if (!containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) {
676 // Slog.e(TAG, "No known USB function in updateUsbNotification");
677 //}
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400678 }
Mike Lockwooda5010432011-07-27 09:50:06 -0400679 }
680 if (id != mUsbNotificationId) {
681 // clear notification if title needs changing
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700682 if (mUsbNotificationId != 0) {
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700683 mNotificationManager.cancelAsUser(null, mUsbNotificationId,
684 UserHandle.ALL);
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700685 mUsbNotificationId = 0;
Mike Lockwooda5010432011-07-27 09:50:06 -0400686 }
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700687 if (id != 0) {
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400688 CharSequence message = r.getText(
689 com.android.internal.R.string.usb_notification_message);
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700690 CharSequence title = r.getText(id);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400691
692 Notification notification = new Notification();
693 notification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
694 notification.when = 0;
695 notification.flags = Notification.FLAG_ONGOING_EVENT;
696 notification.tickerText = title;
697 notification.defaults = 0; // please be quiet
698 notification.sound = null;
699 notification.vibrate = null;
Daniel Sandler49a2ad12012-03-28 15:46:39 -0400700 notification.priority = Notification.PRIORITY_MIN;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400701
Christopher Tate765f97d2011-08-23 20:14:33 -0700702 Intent intent = Intent.makeRestartActivityTask(
703 new ComponentName("com.android.settings",
704 "com.android.settings.UsbSettings"));
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700705 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
706 intent, 0, null, UserHandle.CURRENT);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400707 notification.setLatestEventInfo(mContext, title, message, pi);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700708 mNotificationManager.notifyAsUser(null, id, notification,
709 UserHandle.ALL);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400710 mUsbNotificationId = id;
711 }
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400712 }
713 }
714
715 private void updateAdbNotification() {
716 if (mNotificationManager == null) return;
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700717 final int id = com.android.internal.R.string.adb_active_notification_title;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400718 if (mAdbEnabled && mConnected) {
719 if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
720
721 if (!mAdbNotificationShown) {
722 Resources r = mContext.getResources();
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700723 CharSequence title = r.getText(id);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400724 CharSequence message = r.getText(
725 com.android.internal.R.string.adb_active_notification_message);
726
727 Notification notification = new Notification();
728 notification.icon = com.android.internal.R.drawable.stat_sys_adb;
729 notification.when = 0;
730 notification.flags = Notification.FLAG_ONGOING_EVENT;
731 notification.tickerText = title;
732 notification.defaults = 0; // please be quiet
733 notification.sound = null;
734 notification.vibrate = null;
Daniel Sandlera25079e2012-05-10 10:48:56 -0400735 notification.priority = Notification.PRIORITY_LOW;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400736
Christopher Tate765f97d2011-08-23 20:14:33 -0700737 Intent intent = Intent.makeRestartActivityTask(
738 new ComponentName("com.android.settings",
739 "com.android.settings.DevelopmentSettings"));
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700740 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
741 intent, 0, null, UserHandle.CURRENT);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400742 notification.setLatestEventInfo(mContext, title, message, pi);
743 mAdbNotificationShown = true;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700744 mNotificationManager.notifyAsUser(null, id, notification,
745 UserHandle.ALL);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400746 }
747 } else if (mAdbNotificationShown) {
748 mAdbNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700749 mNotificationManager.cancelAsUser(null, id, UserHandle.ALL);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400750 }
751 }
752
Mike Lockwood02e45692011-06-14 15:43:51 -0400753 public void dump(FileDescriptor fd, PrintWriter pw) {
754 pw.println(" USB Device State:");
755 pw.println(" Current Functions: " + mCurrentFunctions);
756 pw.println(" Default Functions: " + mDefaultFunctions);
757 pw.println(" mConnected: " + mConnected);
758 pw.println(" mConfigured: " + mConfigured);
759 pw.println(" mCurrentAccessory: " + mCurrentAccessory);
Mike Lockwood6ea146c2011-07-10 12:01:16 -0400760 try {
761 pw.println(" Kernel state: "
762 + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
763 pw.println(" Kernel function list: "
764 + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
765 pw.println(" Mass storage backing file: "
766 + FileUtils.readTextFile(new File(MASS_STORAGE_FILE_PATH), 0, null).trim());
767 } catch (IOException e) {
768 pw.println("IOException: " + e);
769 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400770 }
771 }
772
773 /* returns the currently attached USB accessory */
774 public UsbAccessory getCurrentAccessory() {
775 return mHandler.getCurrentAccessory();
776 }
777
778 /* opens the currently attached USB accessory */
Mike Lockwoodabc4ac62011-07-11 10:34:35 -0400779 public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
780 UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
781 if (currentAccessory == null) {
782 throw new IllegalArgumentException("no accessory attached");
Mike Lockwood02e45692011-06-14 15:43:51 -0400783 }
Mike Lockwoodabc4ac62011-07-11 10:34:35 -0400784 if (!currentAccessory.equals(accessory)) {
785 String error = accessory.toString()
786 + " does not match current accessory "
787 + currentAccessory;
788 throw new IllegalArgumentException(error);
789 }
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700790 getCurrentSettings().checkPermission(accessory);
Mike Lockwoodabc4ac62011-07-11 10:34:35 -0400791 return nativeOpenAccessory();
792 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400793
Mike Lockwood166b05e2012-04-24 10:45:18 -0700794 public void setCurrentFunctions(String functions, boolean makeDefault) {
795 if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ") default: " + makeDefault);
796 mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, makeDefault);
Mike Lockwood02e45692011-06-14 15:43:51 -0400797 }
798
799 public void setMassStorageBackingFile(String path) {
800 if (path == null) path = "";
801 try {
802 FileUtils.stringToFile(MASS_STORAGE_FILE_PATH, path);
803 } catch (IOException e) {
804 Slog.e(TAG, "failed to write to " + MASS_STORAGE_FILE_PATH);
805 }
806 }
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400807
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -0600808 private void readOemUsbOverrideConfig() {
809 String[] configList = mContext.getResources().getStringArray(
810 com.android.internal.R.array.config_oemUsbModeOverride);
811
812 if (configList != null) {
813 for (String config: configList) {
814 String[] items = config.split(":");
815 if (items.length == 3) {
816 if (mOemModeMap == null) {
817 mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
818 }
819 List overrideList = mOemModeMap.get(items[0]);
820 if (overrideList == null) {
821 overrideList = new LinkedList<Pair<String, String>>();
822 mOemModeMap.put(items[0], overrideList);
823 }
824 overrideList.add(new Pair<String, String>(items[1], items[2]));
825 }
826 }
827 }
828 }
829
830 private boolean needsOemUsbOverride() {
831 if (mOemModeMap == null) return false;
832
833 String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
834 return (mOemModeMap.get(bootMode) != null) ? true : false;
835 }
836
837 private String processOemUsbOverride(String usbFunctions) {
838 if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
839
840 String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
841
842 List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
843 if (overrides != null) {
844 for (Pair<String, String> pair: overrides) {
845 if (pair.first.equals(usbFunctions)) {
846 Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
847 return pair.second;
848 }
849 }
850 }
851 // return passed in functions as is.
852 return usbFunctions;
853 }
854
Benoit Goby4e68bd42012-04-25 18:06:00 -0700855 public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
856 if (mDebuggingManager != null) {
857 mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
858 }
859 }
860
861 public void denyUsbDebugging() {
862 if (mDebuggingManager != null) {
863 mDebuggingManager.denyUsbDebugging();
864 }
865 }
866
Benoit Gobycd7a17c2012-12-21 16:44:50 -0800867 public void clearUsbDebuggingKeys() {
868 if (mDebuggingManager != null) {
869 mDebuggingManager.clearUsbDebuggingKeys();
870 } else {
871 throw new RuntimeException("Cannot clear Usb Debugging keys, "
872 + "UsbDebuggingManager not enabled");
873 }
874 }
875
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400876 public void dump(FileDescriptor fd, PrintWriter pw) {
Mike Lockwood02e45692011-06-14 15:43:51 -0400877 if (mHandler != null) {
878 mHandler.dump(fd, pw);
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400879 }
Benoit Goby4e68bd42012-04-25 18:06:00 -0700880 if (mDebuggingManager != null) {
881 mDebuggingManager.dump(fd, pw);
882 }
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400883 }
884
885 private native String[] nativeGetAccessoryStrings();
886 private native ParcelFileDescriptor nativeOpenAccessory();
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700887 private native boolean nativeIsStartRequested();
Mike Lockwood166b05e2012-04-24 10:45:18 -0700888 private native int nativeGetAudioMode();
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400889}