blob: c7c2c628709553510d8873dd0759a5f95b6caf32 [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
172 if ("1".equals(SystemProperties.get("ro.adb.secure"))) {
173 mDebuggingManager = new UsbDebuggingManager(context);
174 }
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400175 }
176
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700177 public void setCurrentSettings(UsbSettingsManager settings) {
178 synchronized (mLock) {
179 mCurrentSettings = settings;
180 }
181 }
182
183 private UsbSettingsManager getCurrentSettings() {
184 synchronized (mLock) {
185 return mCurrentSettings;
186 }
187 }
188
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400189 public void systemReady() {
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700190 if (DEBUG) Slog.d(TAG, "systemReady");
Mike Lockwood541c9942011-06-12 19:35:45 -0400191
Mike Lockwood02e45692011-06-14 15:43:51 -0400192 mNotificationManager = (NotificationManager)
193 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
194
Mike Lockwood5787a2d2011-06-17 12:21:39 -0400195 // We do not show the USB notification if the primary volume supports mass storage.
196 // The legacy mass storage UI will be used instead.
197 boolean massStorageSupported = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700198 final StorageManager storageManager = StorageManager.from(mContext);
199 final StorageVolume primary = storageManager.getPrimaryVolume();
200 massStorageSupported = primary != null && primary.allowMassStorage();
Mike Lockwood5787a2d2011-06-17 12:21:39 -0400201 mUseUsbNotification = !massStorageSupported;
202
Mike Lockwood02e45692011-06-14 15:43:51 -0400203 // make sure the ADB_ENABLED setting value matches the current state
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700204 Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0);
Mike Lockwood02e45692011-06-14 15:43:51 -0400205
206 mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
207 }
208
Mike Lockwood166b05e2012-04-24 10:45:18 -0700209 private void startAccessoryMode() {
210 mAccessoryStrings = nativeGetAccessoryStrings();
211 boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
212 // don't start accessory mode if our mandatory strings have not been set
213 boolean enableAccessory = (mAccessoryStrings != null &&
214 mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null &&
215 mAccessoryStrings[UsbAccessory.MODEL_STRING] != null);
216 String functions = null;
217
218 if (enableAccessory && enableAudio) {
219 functions = UsbManager.USB_FUNCTION_ACCESSORY + ","
220 + UsbManager.USB_FUNCTION_AUDIO_SOURCE;
221 } else if (enableAccessory) {
222 functions = UsbManager.USB_FUNCTION_ACCESSORY;
223 } else if (enableAudio) {
224 functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE;
225 }
226
227 if (functions != null) {
228 setCurrentFunctions(functions, false);
229 }
230 }
231
Mike Lockwood629b1492011-07-06 12:47:21 -0400232 private static void initRndisAddress() {
233 // configure RNDIS ethernet address based on our serial number using the same algorithm
234 // we had been previously using in kernel board files
235 final int ETH_ALEN = 6;
236 int address[] = new int[ETH_ALEN];
237 // first byte is 0x02 to signify a locally administered address
238 address[0] = 0x02;
239
240 String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF");
241 int serialLength = serial.length();
242 // XOR the USB serial across the remaining 5 bytes
243 for (int i = 0; i < serialLength; i++) {
244 address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i);
245 }
246 String addrString = String.format("%02X:%02X:%02X:%02X:%02X:%02X",
247 address[0], address[1], address[2], address[3], address[4], address[5]);
248 try {
249 FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString);
250 } catch (IOException e) {
251 Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH);
252 }
253 }
254
Mike Lockwood02e45692011-06-14 15:43:51 -0400255 private static String addFunction(String functions, String function) {
RoboErikdab20722012-03-07 17:53:36 -0800256 if ("none".equals(functions)) {
257 return function;
258 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400259 if (!containsFunction(functions, function)) {
260 if (functions.length() > 0) {
261 functions += ",";
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400262 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400263 functions += function;
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400264 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400265 return functions;
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400266 }
267
Mike Lockwood02e45692011-06-14 15:43:51 -0400268 private static String removeFunction(String functions, String function) {
269 String[] split = functions.split(",");
270 for (int i = 0; i < split.length; i++) {
271 if (function.equals(split[i])) {
272 split[i] = null;
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400273 }
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400274 }
RoboErikdab20722012-03-07 17:53:36 -0800275 if (split.length == 1 && split[0] == null) {
276 return "none";
277 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400278 StringBuilder builder = new StringBuilder();
279 for (int i = 0; i < split.length; i++) {
280 String s = split[i];
281 if (s != null) {
282 if (builder.length() > 0) {
283 builder.append(",");
284 }
285 builder.append(s);
286 }
287 }
288 return builder.toString();
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400289 }
290
Mike Lockwood02e45692011-06-14 15:43:51 -0400291 private static boolean containsFunction(String functions, String function) {
292 int index = functions.indexOf(function);
293 if (index < 0) return false;
294 if (index > 0 && functions.charAt(index - 1) != ',') return false;
295 int charAfter = index + function.length();
296 if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
297 return true;
298 }
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400299
Mike Lockwood02e45692011-06-14 15:43:51 -0400300 private final class UsbHandler extends Handler {
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400301
Mike Lockwood02e45692011-06-14 15:43:51 -0400302 // current USB state
303 private boolean mConnected;
304 private boolean mConfigured;
305 private String mCurrentFunctions;
306 private String mDefaultFunctions;
307 private UsbAccessory mCurrentAccessory;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400308 private int mUsbNotificationId;
309 private boolean mAdbNotificationShown;
Jeff Sharkey27bd34d2012-09-16 12:49:00 -0700310 private int mCurrentUser = UserHandle.USER_NULL;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400311
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700312 private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
Jeff Sharkey27bd34d2012-09-16 12:49:00 -0700313 @Override
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700314 public void onReceive(Context context, Intent intent) {
315 if (DEBUG) Slog.d(TAG, "boot completed");
316 mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
317 }
318 };
319
Jeff Sharkey27bd34d2012-09-16 12:49:00 -0700320 private final BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() {
321 @Override
322 public void onReceive(Context context, Intent intent) {
323 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
324 mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget();
325 }
326 };
327
Mike Lockwood3fd13eb2011-07-13 09:23:45 -0400328 public UsbHandler(Looper looper) {
329 super(looper);
Mike Lockwood02e45692011-06-14 15:43:51 -0400330 try {
Mike Lockwoodc264afeb52011-07-10 11:48:18 -0400331 // persist.sys.usb.config should never be unset. But if it is, set it to "adb"
332 // so we have a chance of debugging what happened.
333 mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -0600334
335 // Check if USB mode needs to be overridden depending on OEM specific bootmode.
336 mDefaultFunctions = processOemUsbOverride(mDefaultFunctions);
337
Mike Lockwoodde296f62011-07-01 14:05:25 -0400338 // sanity check the sys.usb.config system property
339 // this may be necessary if we crashed while switching USB configurations
340 String config = SystemProperties.get("sys.usb.config", "none");
Mike Lockwoodc264afeb52011-07-10 11:48:18 -0400341 if (!config.equals(mDefaultFunctions)) {
342 Slog.w(TAG, "resetting config to persistent property: " + mDefaultFunctions);
343 SystemProperties.set("sys.usb.config", mDefaultFunctions);
Mike Lockwoodde296f62011-07-01 14:05:25 -0400344 }
345
Mike Lockwoodc264afeb52011-07-10 11:48:18 -0400346 mCurrentFunctions = mDefaultFunctions;
Mike Lockwood02e45692011-06-14 15:43:51 -0400347 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
348 updateState(state);
Mike Lockwood02e45692011-06-14 15:43:51 -0400349 mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400350
Mike Lockwood02e45692011-06-14 15:43:51 -0400351 // Upgrade step for previous versions that used persist.service.adb.enable
352 String value = SystemProperties.get("persist.service.adb.enable", "");
353 if (value.length() > 0) {
354 char enable = value.charAt(0);
355 if (enable == '1') {
356 setAdbEnabled(true);
357 } else if (enable == '0') {
358 setAdbEnabled(false);
359 }
360 SystemProperties.set("persist.service.adb.enable", "");
361 }
362
363 // register observer to listen for settings changes
364 mContentResolver.registerContentObserver(
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700365 Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
Mike Lockwood02e45692011-06-14 15:43:51 -0400366 false, new AdbSettingsObserver());
367
368 // Watch for USB configuration changes
369 mUEventObserver.startObserving(USB_STATE_MATCH);
370 mUEventObserver.startObserving(ACCESSORY_START_MATCH);
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700371
Jeff Sharkey27bd34d2012-09-16 12:49:00 -0700372 mContext.registerReceiver(
373 mBootCompletedReceiver, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
374 mContext.registerReceiver(
375 mUserSwitchedReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
Mike Lockwood02e45692011-06-14 15:43:51 -0400376 } catch (Exception e) {
377 Slog.e(TAG, "Error initializing UsbHandler", e);
378 }
379 }
380
381 public void sendMessage(int what, boolean arg) {
382 removeMessages(what);
383 Message m = Message.obtain(this, what);
384 m.arg1 = (arg ? 1 : 0);
385 sendMessage(m);
386 }
387
388 public void sendMessage(int what, Object arg) {
389 removeMessages(what);
390 Message m = Message.obtain(this, what);
391 m.obj = arg;
392 sendMessage(m);
393 }
394
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400395 public void sendMessage(int what, Object arg0, boolean arg1) {
396 removeMessages(what);
397 Message m = Message.obtain(this, what);
398 m.obj = arg0;
399 m.arg1 = (arg1 ? 1 : 0);
400 sendMessage(m);
401 }
402
Mike Lockwood02e45692011-06-14 15:43:51 -0400403 public void updateState(String state) {
404 int connected, configured;
405
406 if ("DISCONNECTED".equals(state)) {
407 connected = 0;
408 configured = 0;
409 } else if ("CONNECTED".equals(state)) {
410 connected = 1;
411 configured = 0;
412 } else if ("CONFIGURED".equals(state)) {
413 connected = 1;
414 configured = 1;
415 } else {
416 Slog.e(TAG, "unknown state " + state);
417 return;
418 }
419 removeMessages(MSG_UPDATE_STATE);
420 Message msg = Message.obtain(this, MSG_UPDATE_STATE);
421 msg.arg1 = connected;
422 msg.arg2 = configured;
423 // debounce disconnects to avoid problems bringing up USB tethering
424 sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
425 }
426
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400427 private boolean waitForState(String state) {
Mike Lockwood02e45692011-06-14 15:43:51 -0400428 // wait for the transition to complete.
429 // give up after 1 second.
430 for (int i = 0; i < 20; i++) {
Mike Lockwood68736cb2011-07-29 11:32:28 -0400431 // State transition is done when sys.usb.state is set to the new configuration
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400432 if (state.equals(SystemProperties.get("sys.usb.state"))) return true;
RoboErikdab20722012-03-07 17:53:36 -0800433 SystemClock.sleep(50);
Mike Lockwood02e45692011-06-14 15:43:51 -0400434 }
Mike Lockwoodfdc0c292011-07-01 11:17:43 -0400435 Slog.e(TAG, "waitForState(" + state + ") FAILED");
Mike Lockwood02e45692011-06-14 15:43:51 -0400436 return false;
437 }
438
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400439 private boolean setUsbConfig(String config) {
Mike Lockwoodfdc0c292011-07-01 11:17:43 -0400440 if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400441 // set the new configuration
442 SystemProperties.set("sys.usb.config", config);
443 return waitForState(config);
444 }
445
Mike Lockwood02e45692011-06-14 15:43:51 -0400446 private void setAdbEnabled(boolean enable) {
Mike Lockwoodde296f62011-07-01 14:05:25 -0400447 if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
Mike Lockwood02e45692011-06-14 15:43:51 -0400448 if (enable != mAdbEnabled) {
449 mAdbEnabled = enable;
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400450 // Due to the persist.sys.usb.config property trigger, changing adb state requires
451 // switching to default function
Mike Lockwood1984e792011-08-03 17:10:43 -0400452 setEnabledFunctions(mDefaultFunctions, true);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400453 updateAdbNotification();
Mike Lockwood02e45692011-06-14 15:43:51 -0400454 }
Benoit Goby4e68bd42012-04-25 18:06:00 -0700455 if (mDebuggingManager != null) {
456 mDebuggingManager.setAdbEnabled(mAdbEnabled);
457 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400458 }
459
Mike Lockwood68736cb2011-07-29 11:32:28 -0400460 private void setEnabledFunctions(String functions, boolean makeDefault) {
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -0600461
462 // Do not update persystent.sys.usb.config if the device is booted up
463 // with OEM specific mode.
464 if (functions != null && makeDefault && !needsOemUsbOverride()) {
465
Mike Lockwood8b4d36e2011-08-02 18:16:26 -0400466 if (mAdbEnabled) {
467 functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
468 } else {
469 functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
470 }
Mike Lockwood68736cb2011-07-29 11:32:28 -0400471 if (!mDefaultFunctions.equals(functions)) {
472 if (!setUsbConfig("none")) {
473 Slog.e(TAG, "Failed to disable USB");
474 // revert to previous configuration if we fail
475 setUsbConfig(mCurrentFunctions);
476 return;
477 }
478 // setting this property will also change the current USB state
479 // via a property trigger
480 SystemProperties.set("persist.sys.usb.config", functions);
481 if (waitForState(functions)) {
482 mCurrentFunctions = functions;
483 mDefaultFunctions = functions;
484 } else {
485 Slog.e(TAG, "Failed to switch persistent USB config to " + functions);
486 // revert to previous configuration if we fail
487 SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
488 }
489 }
490 } else {
491 if (functions == null) {
492 functions = mDefaultFunctions;
493 }
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -0600494
495 // Override with bootmode specific usb mode if needed
496 functions = processOemUsbOverride(functions);
497
Mike Lockwood8b4d36e2011-08-02 18:16:26 -0400498 if (mAdbEnabled) {
499 functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
500 } else {
501 functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
502 }
Mike Lockwood68736cb2011-07-29 11:32:28 -0400503 if (!mCurrentFunctions.equals(functions)) {
504 if (!setUsbConfig("none")) {
505 Slog.e(TAG, "Failed to disable USB");
506 // revert to previous configuration if we fail
507 setUsbConfig(mCurrentFunctions);
508 return;
509 }
510 if (setUsbConfig(functions)) {
511 mCurrentFunctions = functions;
512 } else {
513 Slog.e(TAG, "Failed to switch USB config to " + functions);
514 // revert to previous configuration if we fail
515 setUsbConfig(mCurrentFunctions);
516 }
517 }
518 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400519 }
520
521 private void updateCurrentAccessory() {
522 if (!mHasUsbAccessory) return;
523
524 if (mConfigured) {
Mike Lockwood166b05e2012-04-24 10:45:18 -0700525 if (mAccessoryStrings != null) {
526 mCurrentAccessory = new UsbAccessory(mAccessoryStrings);
Mike Lockwoodfdc0c292011-07-01 11:17:43 -0400527 Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
Mike Lockwood02e45692011-06-14 15:43:51 -0400528 // defer accessoryAttached if system is not ready
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700529 if (mBootCompleted) {
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700530 getCurrentSettings().accessoryAttached(mCurrentAccessory);
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700531 } // else handle in mBootCompletedReceiver
Mike Lockwood02e45692011-06-14 15:43:51 -0400532 } else {
Mike Lockwoodfdc0c292011-07-01 11:17:43 -0400533 Slog.e(TAG, "nativeGetAccessoryStrings failed");
Mike Lockwood02e45692011-06-14 15:43:51 -0400534 }
535 } else if (!mConnected) {
536 // make sure accessory mode is off
537 // and restore default functions
Mike Lockwoodfdc0c292011-07-01 11:17:43 -0400538 Slog.d(TAG, "exited USB accessory mode");
Mike Lockwood68736cb2011-07-29 11:32:28 -0400539 setEnabledFunctions(mDefaultFunctions, false);
Mike Lockwood02e45692011-06-14 15:43:51 -0400540
541 if (mCurrentAccessory != null) {
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700542 if (mBootCompleted) {
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700543 getCurrentSettings().accessoryDetached(mCurrentAccessory);
Mike Lockwood02e45692011-06-14 15:43:51 -0400544 }
545 mCurrentAccessory = null;
Mike Lockwood166b05e2012-04-24 10:45:18 -0700546 mAccessoryStrings = null;
Mike Lockwood02e45692011-06-14 15:43:51 -0400547 }
548 }
549 }
550
551 private void updateUsbState() {
552 // send a sticky broadcast containing current USB state
553 Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
554 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
555 intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
556 intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
557
558 if (mCurrentFunctions != null) {
559 String[] functions = mCurrentFunctions.split(",");
560 for (int i = 0; i < functions.length; i++) {
561 intent.putExtra(functions[i], true);
562 }
563 }
564
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700565 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Mike Lockwood02e45692011-06-14 15:43:51 -0400566 }
567
Mike Lockwoodbf910462012-05-09 16:19:20 -0700568 private void updateAudioSourceFunction() {
569 boolean enabled = containsFunction(mCurrentFunctions,
570 UsbManager.USB_FUNCTION_AUDIO_SOURCE);
571 if (enabled != mAudioSourceEnabled) {
572 // send a sticky broadcast containing current USB state
573 Intent intent = new Intent(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
574 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
575 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
576 intent.putExtra("state", (enabled ? 1 : 0));
577 if (enabled) {
578 try {
579 Scanner scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
580 int card = scanner.nextInt();
581 int device = scanner.nextInt();
582 intent.putExtra("card", card);
583 intent.putExtra("device", device);
584 } catch (FileNotFoundException e) {
585 Slog.e(TAG, "could not open audio source PCM file", e);
586 }
Mike Lockwood9d5a4be2012-04-06 09:41:32 -0700587 }
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700588 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Mike Lockwoodbf910462012-05-09 16:19:20 -0700589 mAudioSourceEnabled = enabled;
Mike Lockwood9d5a4be2012-04-06 09:41:32 -0700590 }
Mike Lockwood9d5a4be2012-04-06 09:41:32 -0700591 }
592
Mike Lockwood02e45692011-06-14 15:43:51 -0400593 @Override
594 public void handleMessage(Message msg) {
Mike Lockwood02e45692011-06-14 15:43:51 -0400595 switch (msg.what) {
596 case MSG_UPDATE_STATE:
597 mConnected = (msg.arg1 == 1);
598 mConfigured = (msg.arg2 == 1);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400599 updateUsbNotification();
600 updateAdbNotification();
Mike Lockwood02e45692011-06-14 15:43:51 -0400601 if (containsFunction(mCurrentFunctions,
602 UsbManager.USB_FUNCTION_ACCESSORY)) {
603 updateCurrentAccessory();
604 }
605
606 if (!mConnected) {
607 // restore defaults when USB is disconnected
Mike Lockwood68736cb2011-07-29 11:32:28 -0400608 setEnabledFunctions(mDefaultFunctions, false);
Mike Lockwood02e45692011-06-14 15:43:51 -0400609 }
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700610 if (mBootCompleted) {
Mike Lockwood02e45692011-06-14 15:43:51 -0400611 updateUsbState();
Mike Lockwoodbf910462012-05-09 16:19:20 -0700612 updateAudioSourceFunction();
Mike Lockwood02e45692011-06-14 15:43:51 -0400613 }
614 break;
615 case MSG_ENABLE_ADB:
616 setAdbEnabled(msg.arg1 == 1);
617 break;
Mike Lockwood166b05e2012-04-24 10:45:18 -0700618 case MSG_SET_CURRENT_FUNCTIONS:
619 String functions = (String)msg.obj;
Mike Lockwoodf59717d2011-06-22 15:19:33 -0400620 boolean makeDefault = (msg.arg1 == 1);
Mike Lockwood166b05e2012-04-24 10:45:18 -0700621 setEnabledFunctions(functions, makeDefault);
Mike Lockwood02e45692011-06-14 15:43:51 -0400622 break;
623 case MSG_SYSTEM_READY:
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400624 updateUsbNotification();
625 updateAdbNotification();
Mike Lockwood02e45692011-06-14 15:43:51 -0400626 updateUsbState();
Mike Lockwoodbf910462012-05-09 16:19:20 -0700627 updateAudioSourceFunction();
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700628 break;
629 case MSG_BOOT_COMPLETED:
630 mBootCompleted = true;
631 if (mCurrentAccessory != null) {
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700632 getCurrentSettings().accessoryAttached(mCurrentAccessory);
Mike Lockwood02e45692011-06-14 15:43:51 -0400633 }
Benoit Goby4e68bd42012-04-25 18:06:00 -0700634 if (mDebuggingManager != null) {
635 mDebuggingManager.setAdbEnabled(mAdbEnabled);
636 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400637 break;
Jeff Sharkey27bd34d2012-09-16 12:49:00 -0700638 case MSG_USER_SWITCHED: {
639 final boolean mtpActive =
640 containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)
641 || containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP);
642 if (mtpActive && mCurrentUser != UserHandle.USER_NULL) {
643 Slog.v(TAG, "Current user switched; resetting USB host stack for MTP");
644 setUsbConfig("none");
645 setUsbConfig(mCurrentFunctions);
646 }
647 mCurrentUser = msg.arg1;
648 break;
649 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400650 }
651 }
652
653 public UsbAccessory getCurrentAccessory() {
654 return mCurrentAccessory;
655 }
656
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400657 private void updateUsbNotification() {
658 if (mNotificationManager == null || !mUseUsbNotification) return;
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700659 int id = 0;
Mike Lockwooda5010432011-07-27 09:50:06 -0400660 Resources r = mContext.getResources();
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400661 if (mConnected) {
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400662 if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) {
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700663 id = com.android.internal.R.string.usb_mtp_notification_title;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400664 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) {
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700665 id = com.android.internal.R.string.usb_ptp_notification_title;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400666 } else if (containsFunction(mCurrentFunctions,
667 UsbManager.USB_FUNCTION_MASS_STORAGE)) {
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700668 id = com.android.internal.R.string.usb_cd_installer_notification_title;
Mike Lockwood6e680de2011-07-21 15:36:09 -0700669 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) {
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700670 id = com.android.internal.R.string.usb_accessory_notification_title;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400671 } else {
Mike Lockwooda5010432011-07-27 09:50:06 -0400672 // There is a different notification for USB tethering so we don't need one here
Dianne Hackborn7ff30112012-11-08 11:12:09 -0800673 //if (!containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) {
674 // Slog.e(TAG, "No known USB function in updateUsbNotification");
675 //}
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400676 }
Mike Lockwooda5010432011-07-27 09:50:06 -0400677 }
678 if (id != mUsbNotificationId) {
679 // clear notification if title needs changing
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700680 if (mUsbNotificationId != 0) {
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700681 mNotificationManager.cancelAsUser(null, mUsbNotificationId,
682 UserHandle.ALL);
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700683 mUsbNotificationId = 0;
Mike Lockwooda5010432011-07-27 09:50:06 -0400684 }
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700685 if (id != 0) {
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400686 CharSequence message = r.getText(
687 com.android.internal.R.string.usb_notification_message);
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700688 CharSequence title = r.getText(id);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400689
690 Notification notification = new Notification();
691 notification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
692 notification.when = 0;
693 notification.flags = Notification.FLAG_ONGOING_EVENT;
694 notification.tickerText = title;
695 notification.defaults = 0; // please be quiet
696 notification.sound = null;
697 notification.vibrate = null;
Daniel Sandler49a2ad12012-03-28 15:46:39 -0400698 notification.priority = Notification.PRIORITY_MIN;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400699
Christopher Tate765f97d2011-08-23 20:14:33 -0700700 Intent intent = Intent.makeRestartActivityTask(
701 new ComponentName("com.android.settings",
702 "com.android.settings.UsbSettings"));
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700703 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
704 intent, 0, null, UserHandle.CURRENT);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400705 notification.setLatestEventInfo(mContext, title, message, pi);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700706 mNotificationManager.notifyAsUser(null, id, notification,
707 UserHandle.ALL);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400708 mUsbNotificationId = id;
709 }
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400710 }
711 }
712
713 private void updateAdbNotification() {
714 if (mNotificationManager == null) return;
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700715 final int id = com.android.internal.R.string.adb_active_notification_title;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400716 if (mAdbEnabled && mConnected) {
717 if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
718
719 if (!mAdbNotificationShown) {
720 Resources r = mContext.getResources();
Mike Lockwoodfadd2b82011-08-16 13:34:34 -0700721 CharSequence title = r.getText(id);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400722 CharSequence message = r.getText(
723 com.android.internal.R.string.adb_active_notification_message);
724
725 Notification notification = new Notification();
726 notification.icon = com.android.internal.R.drawable.stat_sys_adb;
727 notification.when = 0;
728 notification.flags = Notification.FLAG_ONGOING_EVENT;
729 notification.tickerText = title;
730 notification.defaults = 0; // please be quiet
731 notification.sound = null;
732 notification.vibrate = null;
Daniel Sandlera25079e2012-05-10 10:48:56 -0400733 notification.priority = Notification.PRIORITY_LOW;
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400734
Christopher Tate765f97d2011-08-23 20:14:33 -0700735 Intent intent = Intent.makeRestartActivityTask(
736 new ComponentName("com.android.settings",
737 "com.android.settings.DevelopmentSettings"));
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700738 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
739 intent, 0, null, UserHandle.CURRENT);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400740 notification.setLatestEventInfo(mContext, title, message, pi);
741 mAdbNotificationShown = true;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700742 mNotificationManager.notifyAsUser(null, id, notification,
743 UserHandle.ALL);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400744 }
745 } else if (mAdbNotificationShown) {
746 mAdbNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700747 mNotificationManager.cancelAsUser(null, id, UserHandle.ALL);
Mike Lockwoodd8404d22011-06-23 16:04:29 -0400748 }
749 }
750
Mike Lockwood02e45692011-06-14 15:43:51 -0400751 public void dump(FileDescriptor fd, PrintWriter pw) {
752 pw.println(" USB Device State:");
753 pw.println(" Current Functions: " + mCurrentFunctions);
754 pw.println(" Default Functions: " + mDefaultFunctions);
755 pw.println(" mConnected: " + mConnected);
756 pw.println(" mConfigured: " + mConfigured);
757 pw.println(" mCurrentAccessory: " + mCurrentAccessory);
Mike Lockwood6ea146c2011-07-10 12:01:16 -0400758 try {
759 pw.println(" Kernel state: "
760 + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
761 pw.println(" Kernel function list: "
762 + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
763 pw.println(" Mass storage backing file: "
764 + FileUtils.readTextFile(new File(MASS_STORAGE_FILE_PATH), 0, null).trim());
765 } catch (IOException e) {
766 pw.println("IOException: " + e);
767 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400768 }
769 }
770
771 /* returns the currently attached USB accessory */
772 public UsbAccessory getCurrentAccessory() {
773 return mHandler.getCurrentAccessory();
774 }
775
776 /* opens the currently attached USB accessory */
Mike Lockwoodabc4ac62011-07-11 10:34:35 -0400777 public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
778 UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
779 if (currentAccessory == null) {
780 throw new IllegalArgumentException("no accessory attached");
Mike Lockwood02e45692011-06-14 15:43:51 -0400781 }
Mike Lockwoodabc4ac62011-07-11 10:34:35 -0400782 if (!currentAccessory.equals(accessory)) {
783 String error = accessory.toString()
784 + " does not match current accessory "
785 + currentAccessory;
786 throw new IllegalArgumentException(error);
787 }
Jeff Sharkeyfc3f24b2012-10-01 21:45:52 -0700788 getCurrentSettings().checkPermission(accessory);
Mike Lockwoodabc4ac62011-07-11 10:34:35 -0400789 return nativeOpenAccessory();
790 }
Mike Lockwood02e45692011-06-14 15:43:51 -0400791
Mike Lockwood166b05e2012-04-24 10:45:18 -0700792 public void setCurrentFunctions(String functions, boolean makeDefault) {
793 if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ") default: " + makeDefault);
794 mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, makeDefault);
Mike Lockwood02e45692011-06-14 15:43:51 -0400795 }
796
797 public void setMassStorageBackingFile(String path) {
798 if (path == null) path = "";
799 try {
800 FileUtils.stringToFile(MASS_STORAGE_FILE_PATH, path);
801 } catch (IOException e) {
802 Slog.e(TAG, "failed to write to " + MASS_STORAGE_FILE_PATH);
803 }
804 }
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400805
Kazuhiro Ondoafd8f182012-02-06 17:35:50 -0600806 private void readOemUsbOverrideConfig() {
807 String[] configList = mContext.getResources().getStringArray(
808 com.android.internal.R.array.config_oemUsbModeOverride);
809
810 if (configList != null) {
811 for (String config: configList) {
812 String[] items = config.split(":");
813 if (items.length == 3) {
814 if (mOemModeMap == null) {
815 mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
816 }
817 List overrideList = mOemModeMap.get(items[0]);
818 if (overrideList == null) {
819 overrideList = new LinkedList<Pair<String, String>>();
820 mOemModeMap.put(items[0], overrideList);
821 }
822 overrideList.add(new Pair<String, String>(items[1], items[2]));
823 }
824 }
825 }
826 }
827
828 private boolean needsOemUsbOverride() {
829 if (mOemModeMap == null) return false;
830
831 String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
832 return (mOemModeMap.get(bootMode) != null) ? true : false;
833 }
834
835 private String processOemUsbOverride(String usbFunctions) {
836 if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
837
838 String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
839
840 List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
841 if (overrides != null) {
842 for (Pair<String, String> pair: overrides) {
843 if (pair.first.equals(usbFunctions)) {
844 Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
845 return pair.second;
846 }
847 }
848 }
849 // return passed in functions as is.
850 return usbFunctions;
851 }
852
Benoit Goby4e68bd42012-04-25 18:06:00 -0700853 public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
854 if (mDebuggingManager != null) {
855 mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
856 }
857 }
858
859 public void denyUsbDebugging() {
860 if (mDebuggingManager != null) {
861 mDebuggingManager.denyUsbDebugging();
862 }
863 }
864
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400865 public void dump(FileDescriptor fd, PrintWriter pw) {
Mike Lockwood02e45692011-06-14 15:43:51 -0400866 if (mHandler != null) {
867 mHandler.dump(fd, pw);
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400868 }
Benoit Goby4e68bd42012-04-25 18:06:00 -0700869 if (mDebuggingManager != null) {
870 mDebuggingManager.dump(fd, pw);
871 }
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400872 }
873
874 private native String[] nativeGetAccessoryStrings();
875 private native ParcelFileDescriptor nativeOpenAccessory();
Mike Lockwoodd462ecf2011-07-21 13:55:16 -0700876 private native boolean nativeIsStartRequested();
Mike Lockwood166b05e2012-04-24 10:45:18 -0700877 private native int nativeGetAudioMode();
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400878}