UsbDeviceManager.java revision 68736cbf938935f7d7e1eb2b3f9ec911fcb0da72
146d0adf8256a42416584765625852b6e48497c90Mike Lockwood/*
246d0adf8256a42416584765625852b6e48497c90Mike Lockwood * Copyright (C) 2011 The Android Open Source Project
346d0adf8256a42416584765625852b6e48497c90Mike Lockwood *
446d0adf8256a42416584765625852b6e48497c90Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
546d0adf8256a42416584765625852b6e48497c90Mike Lockwood * you may not use this file except in compliance with the License.
646d0adf8256a42416584765625852b6e48497c90Mike Lockwood * You may obtain a copy of the License at
746d0adf8256a42416584765625852b6e48497c90Mike Lockwood *
846d0adf8256a42416584765625852b6e48497c90Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
946d0adf8256a42416584765625852b6e48497c90Mike Lockwood *
1046d0adf8256a42416584765625852b6e48497c90Mike Lockwood * Unless required by applicable law or agreed to in writing, software
1146d0adf8256a42416584765625852b6e48497c90Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
1246d0adf8256a42416584765625852b6e48497c90Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1346d0adf8256a42416584765625852b6e48497c90Mike Lockwood * See the License for the specific language governing permissions an
1446d0adf8256a42416584765625852b6e48497c90Mike Lockwood * limitations under the License.
1546d0adf8256a42416584765625852b6e48497c90Mike Lockwood */
1646d0adf8256a42416584765625852b6e48497c90Mike Lockwood
1746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodpackage com.android.server.usb;
1846d0adf8256a42416584765625852b6e48497c90Mike Lockwood
1946d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.app.PendingIntent;
20541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwoodimport android.app.Notification;
21541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwoodimport android.app.NotificationManager;
22d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwoodimport android.content.BroadcastReceiver;
23541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwoodimport android.content.ComponentName;
2446d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.content.ContentResolver;
2546d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.content.Context;
2646d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.content.Intent;
2746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.content.IntentFilter;
2846d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.content.pm.PackageManager;
29541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwoodimport android.content.res.Resources;
30541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwoodimport android.database.ContentObserver;
3146d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbAccessory;
3246d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbManager;
3346d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.net.Uri;
3446d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.Binder;
3546d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.Bundle;
3602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwoodimport android.os.FileUtils;
3746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.Handler;
3802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwoodimport android.os.HandlerThread;
3902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwoodimport android.os.Looper;
4046d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.Message;
4146d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.Parcelable;
4246d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.ParcelFileDescriptor;
4302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwoodimport android.os.Process;
4402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwoodimport android.os.storage.StorageManager;
4502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwoodimport android.os.storage.StorageVolume;
46541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwoodimport android.os.SystemProperties;
4746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.UEventObserver;
4846d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.provider.Settings;
4946d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.util.Slog;
5046d0adf8256a42416584765625852b6e48497c90Mike Lockwood
5146d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.io.File;
5246d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.io.FileDescriptor;
5346d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.io.FileNotFoundException;
5402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwoodimport java.io.IOException;
5546d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.io.PrintWriter;
5646d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.util.ArrayList;
5746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.util.List;
5846d0adf8256a42416584765625852b6e48497c90Mike Lockwood
5946d0adf8256a42416584765625852b6e48497c90Mike Lockwood/**
6046d0adf8256a42416584765625852b6e48497c90Mike Lockwood * UsbDeviceManager manages USB state in device mode.
6146d0adf8256a42416584765625852b6e48497c90Mike Lockwood */
6246d0adf8256a42416584765625852b6e48497c90Mike Lockwoodpublic class UsbDeviceManager {
6302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
6446d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private static final String TAG = UsbDeviceManager.class.getSimpleName();
65fdc0c2984d05e32954608f46514c4cbe3a5a9424Mike Lockwood    private static final boolean DEBUG = false;
6646d0adf8256a42416584765625852b6e48497c90Mike Lockwood
6702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    private static final String USB_STATE_MATCH =
6802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            "DEVPATH=/devices/virtual/android_usb/android0";
6902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    private static final String ACCESSORY_START_MATCH =
7002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            "DEVPATH=/devices/virtual/misc/usb_accessory";
7102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    private static final String FUNCTIONS_PATH =
7202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            "/sys/class/android_usb/android0/functions";
7302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    private static final String STATE_PATH =
7402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            "/sys/class/android_usb/android0/state";
7502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    private static final String MASS_STORAGE_FILE_PATH =
76629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood            "/sys/class/android_usb/android0/f_mass_storage/lun/file";
77629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood    private static final String RNDIS_ETH_ADDR_PATH =
78629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood            "/sys/class/android_usb/android0/f_rndis/ethaddr";
7946d0adf8256a42416584765625852b6e48497c90Mike Lockwood
8046d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private static final int MSG_UPDATE_STATE = 0;
8102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    private static final int MSG_ENABLE_ADB = 1;
82f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood    private static final int MSG_SET_CURRENT_FUNCTION = 2;
83f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood    private static final int MSG_SYSTEM_READY = 3;
84d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood    private static final int MSG_BOOT_COMPLETED = 4;
8546d0adf8256a42416584765625852b6e48497c90Mike Lockwood
8646d0adf8256a42416584765625852b6e48497c90Mike Lockwood    // Delay for debouncing USB disconnects.
8746d0adf8256a42416584765625852b6e48497c90Mike Lockwood    // We often get rapid connect/disconnect events when enabling USB functions,
8846d0adf8256a42416584765625852b6e48497c90Mike Lockwood    // which need debouncing.
8946d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private static final int UPDATE_DELAY = 1000;
9046d0adf8256a42416584765625852b6e48497c90Mike Lockwood
9102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    private UsbHandler mHandler;
92d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood    private boolean mBootCompleted;
9346d0adf8256a42416584765625852b6e48497c90Mike Lockwood
9446d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private final Context mContext;
9502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    private final ContentResolver mContentResolver;
9646d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private final UsbSettingsManager mSettingsManager;
97541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood    private NotificationManager mNotificationManager;
9846d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private final boolean mHasUsbAccessory;
995787a2d5b4e5bd60087eb7fbb13c97c7d0ba113eMike Lockwood    private boolean mUseUsbNotification;
100541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood    private boolean mAdbEnabled;
101541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood
102541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood    private class AdbSettingsObserver extends ContentObserver {
103541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood        public AdbSettingsObserver() {
104541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood            super(null);
105541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood        }
106541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood        @Override
107541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood        public void onChange(boolean selfChange) {
10802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            boolean enable = (Settings.Secure.getInt(mContentResolver,
10902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    Settings.Secure.ADB_ENABLED, 0) > 0);
11002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            mHandler.sendMessage(MSG_ENABLE_ADB, enable);
111541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood        }
112541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood    }
113541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood
11446d0adf8256a42416584765625852b6e48497c90Mike Lockwood    /*
11546d0adf8256a42416584765625852b6e48497c90Mike Lockwood     * Listens for uevent messages from the kernel to monitor the USB state
11646d0adf8256a42416584765625852b6e48497c90Mike Lockwood     */
11746d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private final UEventObserver mUEventObserver = new UEventObserver() {
11846d0adf8256a42416584765625852b6e48497c90Mike Lockwood        @Override
11946d0adf8256a42416584765625852b6e48497c90Mike Lockwood        public void onUEvent(UEventObserver.UEvent event) {
120fdc0c2984d05e32954608f46514c4cbe3a5a9424Mike Lockwood            if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());
12146d0adf8256a42416584765625852b6e48497c90Mike Lockwood
12202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            String state = event.get("USB_STATE");
12302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            String accessory = event.get("ACCESSORY");
12402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            if (state != null) {
12502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                mHandler.updateState(state);
12602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            } else if ("START".equals(accessory)) {
127fdc0c2984d05e32954608f46514c4cbe3a5a9424Mike Lockwood                if (DEBUG) Slog.d(TAG, "got accessory start");
128f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood                setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false);
12946d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
13046d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
13146d0adf8256a42416584765625852b6e48497c90Mike Lockwood    };
13246d0adf8256a42416584765625852b6e48497c90Mike Lockwood
13346d0adf8256a42416584765625852b6e48497c90Mike Lockwood    public UsbDeviceManager(Context context, UsbSettingsManager settingsManager) {
13446d0adf8256a42416584765625852b6e48497c90Mike Lockwood        mContext = context;
135541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood        mContentResolver = context.getContentResolver();
13646d0adf8256a42416584765625852b6e48497c90Mike Lockwood        mSettingsManager = settingsManager;
13746d0adf8256a42416584765625852b6e48497c90Mike Lockwood        PackageManager pm = mContext.getPackageManager();
13846d0adf8256a42416584765625852b6e48497c90Mike Lockwood        mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
139629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        initRndisAddress();
14046d0adf8256a42416584765625852b6e48497c90Mike Lockwood
14102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        // create a thread for our Handler
14202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        HandlerThread thread = new HandlerThread("UsbDeviceManager",
1433fd13eb6322e09f1ffe5476e28d55732da391151Mike Lockwood                Process.THREAD_PRIORITY_BACKGROUND);
14402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        thread.start();
1453fd13eb6322e09f1ffe5476e28d55732da391151Mike Lockwood        mHandler = new UsbHandler(thread.getLooper());
146d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood
147d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood        if (nativeIsStartRequested()) {
148d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood            if (DEBUG) Slog.d(TAG, "accessory attached at boot");
149d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood            setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false);
150d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood        }
15102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    }
15202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
15302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    public void systemReady() {
154d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood        if (DEBUG) Slog.d(TAG, "systemReady");
15502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
15602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        mNotificationManager = (NotificationManager)
15702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
15846d0adf8256a42416584765625852b6e48497c90Mike Lockwood
1595787a2d5b4e5bd60087eb7fbb13c97c7d0ba113eMike Lockwood        // We do not show the USB notification if the primary volume supports mass storage.
1605787a2d5b4e5bd60087eb7fbb13c97c7d0ba113eMike Lockwood        // The legacy mass storage UI will be used instead.
1615787a2d5b4e5bd60087eb7fbb13c97c7d0ba113eMike Lockwood        boolean massStorageSupported = false;
1625787a2d5b4e5bd60087eb7fbb13c97c7d0ba113eMike Lockwood        StorageManager storageManager = (StorageManager)
1635787a2d5b4e5bd60087eb7fbb13c97c7d0ba113eMike Lockwood                mContext.getSystemService(Context.STORAGE_SERVICE);
1645787a2d5b4e5bd60087eb7fbb13c97c7d0ba113eMike Lockwood        StorageVolume[] volumes = storageManager.getVolumeList();
1655787a2d5b4e5bd60087eb7fbb13c97c7d0ba113eMike Lockwood        if (volumes.length > 0) {
1665787a2d5b4e5bd60087eb7fbb13c97c7d0ba113eMike Lockwood            massStorageSupported = volumes[0].allowMassStorage();
1675787a2d5b4e5bd60087eb7fbb13c97c7d0ba113eMike Lockwood        }
1685787a2d5b4e5bd60087eb7fbb13c97c7d0ba113eMike Lockwood        mUseUsbNotification = !massStorageSupported;
1695787a2d5b4e5bd60087eb7fbb13c97c7d0ba113eMike Lockwood
17002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        // make sure the ADB_ENABLED setting value matches the current state
17102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED, mAdbEnabled ? 1 : 0);
172541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood
17302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
17402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    }
175541c9949ae9c05636d3e0442aa5080815121a042Mike Lockwood
176629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood    private static void initRndisAddress() {
177629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        // configure RNDIS ethernet address based on our serial number using the same algorithm
178629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        // we had been previously using in kernel board files
179629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        final int ETH_ALEN = 6;
180629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        int address[] = new int[ETH_ALEN];
181629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        // first byte is 0x02 to signify a locally administered address
182629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        address[0] = 0x02;
183629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood
184629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF");
185629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        int serialLength = serial.length();
186629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        // XOR the USB serial across the remaining 5 bytes
187629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        for (int i = 0; i < serialLength; i++) {
188629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood            address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i);
189629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        }
190629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        String addrString = String.format("%02X:%02X:%02X:%02X:%02X:%02X",
191629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood            address[0], address[1], address[2], address[3], address[4], address[5]);
192629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        try {
193629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood            FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString);
194629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        } catch (IOException e) {
195629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood           Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH);
196629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood        }
197629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood    }
198629b149ff584bc247f68014a676101d1d5787d27Mike Lockwood
19902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood     private static String addFunction(String functions, String function) {
20002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        if (!containsFunction(functions, function)) {
20102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            if (functions.length() > 0) {
20202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                functions += ",";
20346d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
20402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            functions += function;
20546d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
20602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        return functions;
20746d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
20846d0adf8256a42416584765625852b6e48497c90Mike Lockwood
20902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    private static String removeFunction(String functions, String function) {
21002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        String[] split = functions.split(",");
21102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        for (int i = 0; i < split.length; i++) {
21202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            if (function.equals(split[i])) {
21302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                split[i] = null;
21402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            }
21502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        }
21602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        StringBuilder builder = new StringBuilder();
21702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood         for (int i = 0; i < split.length; i++) {
21802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            String s = split[i];
21902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            if (s != null) {
22002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                if (builder.length() > 0) {
22102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    builder.append(",");
22202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                }
22302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                builder.append(s);
22402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            }
22502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        }
22602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        return builder.toString();
22702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    }
22846d0adf8256a42416584765625852b6e48497c90Mike Lockwood
22902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    private static boolean containsFunction(String functions, String function) {
23002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        int index = functions.indexOf(function);
23102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        if (index < 0) return false;
23202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        if (index > 0 && functions.charAt(index - 1) != ',') return false;
23302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        int charAfter = index + function.length();
23402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
23502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        return true;
23602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    }
23702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
23802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    private final class UsbHandler extends Handler {
23902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
24002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        // current USB state
24102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        private boolean mConnected;
24202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        private boolean mConfigured;
24302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        private String mCurrentFunctions;
24402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        private String mDefaultFunctions;
24502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        private UsbAccessory mCurrentAccessory;
246d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood        private int mUsbNotificationId;
247d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood        private boolean mAdbNotificationShown;
248d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood
249d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood        private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
250d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood            public void onReceive(Context context, Intent intent) {
251d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood                if (DEBUG) Slog.d(TAG, "boot completed");
252d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood                mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
253d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood            }
254d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood        };
255d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood
256d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood        private static final int NOTIFICATION_NONE = 0;
257d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood        private static final int NOTIFICATION_MTP = 1;
258d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood        private static final int NOTIFICATION_PTP = 2;
259d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood        private static final int NOTIFICATION_INSTALLER = 3;
2606e680dea3bc9e2d4ba1a09f428c303cd2a59c051Mike Lockwood        private static final int NOTIFICATION_ACCESSORY = 4;
2616e680dea3bc9e2d4ba1a09f428c303cd2a59c051Mike Lockwood        private static final int NOTIFICATION_ADB = 5;
26202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
2633fd13eb6322e09f1ffe5476e28d55732da391151Mike Lockwood        public UsbHandler(Looper looper) {
2643fd13eb6322e09f1ffe5476e28d55732da391151Mike Lockwood            super(looper);
26502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            try {
266c264afeb5528733a215a472e761b51cc59bba454Mike Lockwood                // persist.sys.usb.config should never be unset.  But if it is, set it to "adb"
267c264afeb5528733a215a472e761b51cc59bba454Mike Lockwood                // so we have a chance of debugging what happened.
268c264afeb5528733a215a472e761b51cc59bba454Mike Lockwood                mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");
269de296f64483713fdf164f3e8bf41dc12d1cff59eMike Lockwood                // sanity check the sys.usb.config system property
270de296f64483713fdf164f3e8bf41dc12d1cff59eMike Lockwood                // this may be necessary if we crashed while switching USB configurations
271de296f64483713fdf164f3e8bf41dc12d1cff59eMike Lockwood                String config = SystemProperties.get("sys.usb.config", "none");
272c264afeb5528733a215a472e761b51cc59bba454Mike Lockwood                if (!config.equals(mDefaultFunctions)) {
273c264afeb5528733a215a472e761b51cc59bba454Mike Lockwood                    Slog.w(TAG, "resetting config to persistent property: " + mDefaultFunctions);
274c264afeb5528733a215a472e761b51cc59bba454Mike Lockwood                    SystemProperties.set("sys.usb.config", mDefaultFunctions);
275de296f64483713fdf164f3e8bf41dc12d1cff59eMike Lockwood                }
276de296f64483713fdf164f3e8bf41dc12d1cff59eMike Lockwood
277c264afeb5528733a215a472e761b51cc59bba454Mike Lockwood                mCurrentFunctions = mDefaultFunctions;
27802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
27902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                updateState(state);
28002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
28102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
28202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                // Upgrade step for previous versions that used persist.service.adb.enable
28302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                String value = SystemProperties.get("persist.service.adb.enable", "");
28402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                if (value.length() > 0) {
28502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    char enable = value.charAt(0);
28602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    if (enable == '1') {
28702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                        setAdbEnabled(true);
28802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    } else if (enable == '0') {
28902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                        setAdbEnabled(false);
29002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    }
29102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    SystemProperties.set("persist.service.adb.enable", "");
29202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                }
29302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
29402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                // register observer to listen for settings changes
29502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                mContentResolver.registerContentObserver(
29602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                        Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
29702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                                false, new AdbSettingsObserver());
29802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
29902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                // Watch for USB configuration changes
30002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                mUEventObserver.startObserving(USB_STATE_MATCH);
30102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                mUEventObserver.startObserving(ACCESSORY_START_MATCH);
302d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood
303d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood                mContext.registerReceiver(mBootCompletedReceiver,
304d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood                        new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
30502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            } catch (Exception e) {
30602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                Slog.e(TAG, "Error initializing UsbHandler", e);
30702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            }
30846d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
30902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
31002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        public void sendMessage(int what, boolean arg) {
31102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            removeMessages(what);
31202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            Message m = Message.obtain(this, what);
31302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            m.arg1 = (arg ? 1 : 0);
31402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            sendMessage(m);
31546d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
31646d0adf8256a42416584765625852b6e48497c90Mike Lockwood
31702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        public void sendMessage(int what, Object arg) {
31802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            removeMessages(what);
31902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            Message m = Message.obtain(this, what);
32002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            m.obj = arg;
32102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            sendMessage(m);
32202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        }
32302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
324f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood        public void sendMessage(int what, Object arg0, boolean arg1) {
325f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood            removeMessages(what);
326f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood            Message m = Message.obtain(this, what);
327f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood            m.obj = arg0;
328f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood            m.arg1 = (arg1 ? 1 : 0);
329f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood            sendMessage(m);
330f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood        }
331f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood
33202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        public void updateState(String state) {
33302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            int connected, configured;
33402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
33502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            if ("DISCONNECTED".equals(state)) {
33602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                connected = 0;
33702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                configured = 0;
33802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            } else if ("CONNECTED".equals(state)) {
33902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                connected = 1;
34002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                configured = 0;
34102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            } else if ("CONFIGURED".equals(state)) {
34202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                connected = 1;
34302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                configured = 1;
34402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            } else {
34502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                Slog.e(TAG, "unknown state " + state);
34602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                return;
34702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            }
34802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            removeMessages(MSG_UPDATE_STATE);
34902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            Message msg = Message.obtain(this, MSG_UPDATE_STATE);
35002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            msg.arg1 = connected;
35102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            msg.arg2 = configured;
35202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            // debounce disconnects to avoid problems bringing up USB tethering
35302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
35402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        }
35502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
356f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood        private boolean waitForState(String state) {
35702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            // wait for the transition to complete.
35802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            // give up after 1 second.
35902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            for (int i = 0; i < 20; i++) {
36068736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                // State transition is done when sys.usb.state is set to the new configuration
361f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood                if (state.equals(SystemProperties.get("sys.usb.state"))) return true;
36202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                try {
36302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    // try again in 50ms
36402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    Thread.sleep(50);
36502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                } catch (InterruptedException e) {
36602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                }
36702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            }
368fdc0c2984d05e32954608f46514c4cbe3a5a9424Mike Lockwood            Slog.e(TAG, "waitForState(" + state + ") FAILED");
36902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            return false;
37002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        }
37102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
372f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood        private boolean setUsbConfig(String config) {
373fdc0c2984d05e32954608f46514c4cbe3a5a9424Mike Lockwood            if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
374f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood            // set the new configuration
375f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood            SystemProperties.set("sys.usb.config", config);
376f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood            return waitForState(config);
377f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood        }
378f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood
37902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        private void setAdbEnabled(boolean enable) {
380de296f64483713fdf164f3e8bf41dc12d1cff59eMike Lockwood            if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
38102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            if (enable != mAdbEnabled) {
38202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                mAdbEnabled = enable;
383f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood                // Due to the persist.sys.usb.config property trigger, changing adb state requires
384f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood                // switching to default function
38568736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                setEnabledFunctions(mDefaultFunctions, false);
386d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                updateAdbNotification();
38702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            }
38802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        }
38902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
39068736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood        private void setEnabledFunctions(String functions, boolean makeDefault) {
39102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            if (mAdbEnabled) {
39268736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
39302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            } else {
39468736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
39568736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood            }
39668736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood
39768736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood            if (functions != null && makeDefault) {
39868736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                if (!mDefaultFunctions.equals(functions)) {
39968736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    if (!setUsbConfig("none")) {
40068736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        Slog.e(TAG, "Failed to disable USB");
40168736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        // revert to previous configuration if we fail
40268736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        setUsbConfig(mCurrentFunctions);
40368736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        return;
40468736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    }
40568736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    // setting this property will also change the current USB state
40668736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    // via a property trigger
40768736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    SystemProperties.set("persist.sys.usb.config", functions);
40868736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    if (waitForState(functions)) {
40968736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        mCurrentFunctions = functions;
41068736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        mDefaultFunctions = functions;
41168736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    } else {
41268736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        Slog.e(TAG, "Failed to switch persistent USB config to " + functions);
41368736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        // revert to previous configuration if we fail
41468736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
41568736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    }
41668736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                }
41768736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood            } else {
41868736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                if (functions == null) {
41968736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    functions = mDefaultFunctions;
42068736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                }
42168736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                if (!mCurrentFunctions.equals(functions)) {
42268736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    if (!setUsbConfig("none")) {
42368736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        Slog.e(TAG, "Failed to disable USB");
42468736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        // revert to previous configuration if we fail
42568736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        setUsbConfig(mCurrentFunctions);
42668736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        return;
42768736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    }
42868736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    if (setUsbConfig(functions)) {
42968736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        mCurrentFunctions = functions;
43068736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    } else {
43168736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        Slog.e(TAG, "Failed to switch USB config to " + functions);
43268736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        // revert to previous configuration if we fail
43368736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        setUsbConfig(mCurrentFunctions);
43468736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    }
43568736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                }
43602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            }
43702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        }
43802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
43902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        private void updateCurrentAccessory() {
44002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            if (!mHasUsbAccessory) return;
44102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
44202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            if (mConfigured) {
44302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                String[] strings = nativeGetAccessoryStrings();
44402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                if (strings != null) {
44502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    mCurrentAccessory = new UsbAccessory(strings);
446fdc0c2984d05e32954608f46514c4cbe3a5a9424Mike Lockwood                    Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
44702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    // defer accessoryAttached if system is not ready
448d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood                    if (mBootCompleted) {
44902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                        mSettingsManager.accessoryAttached(mCurrentAccessory);
450d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood                    } // else handle in mBootCompletedReceiver
45102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                } else {
452fdc0c2984d05e32954608f46514c4cbe3a5a9424Mike Lockwood                    Slog.e(TAG, "nativeGetAccessoryStrings failed");
45302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                }
45402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            } else if (!mConnected) {
45502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                // make sure accessory mode is off
45602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                // and restore default functions
457fdc0c2984d05e32954608f46514c4cbe3a5a9424Mike Lockwood                Slog.d(TAG, "exited USB accessory mode");
45868736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                setEnabledFunctions(mDefaultFunctions, false);
45902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
46002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                if (mCurrentAccessory != null) {
461d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood                    if (mBootCompleted) {
46202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                        mSettingsManager.accessoryDetached(mCurrentAccessory);
46302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    }
46402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    mCurrentAccessory = null;
46546d0adf8256a42416584765625852b6e48497c90Mike Lockwood                }
46646d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
46746d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
46846d0adf8256a42416584765625852b6e48497c90Mike Lockwood
46902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        private void updateUsbState() {
47002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            // send a sticky broadcast containing current USB state
47102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
47202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
47302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
47402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
47502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
47602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            if (mCurrentFunctions != null) {
47702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                String[] functions = mCurrentFunctions.split(",");
47802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                for (int i = 0; i < functions.length; i++) {
47902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    intent.putExtra(functions[i], true);
48002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                }
48146d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
48202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
48302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            mContext.sendStickyBroadcast(intent);
48446d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
48546d0adf8256a42416584765625852b6e48497c90Mike Lockwood
48602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        @Override
48702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        public void handleMessage(Message msg) {
48802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            switch (msg.what) {
48902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                case MSG_UPDATE_STATE:
49002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    mConnected = (msg.arg1 == 1);
49102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    mConfigured = (msg.arg2 == 1);
492d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    updateUsbNotification();
493d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    updateAdbNotification();
49402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    if (containsFunction(mCurrentFunctions,
49502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                            UsbManager.USB_FUNCTION_ACCESSORY)) {
49602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                        updateCurrentAccessory();
49702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    }
49802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
49902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    if (!mConnected) {
50002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                        // restore defaults when USB is disconnected
50168736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                        setEnabledFunctions(mDefaultFunctions, false);
50202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    }
503d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood                    if (mBootCompleted) {
50402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                        updateUsbState();
50502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    }
50602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    break;
50702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                case MSG_ENABLE_ADB:
50802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    setAdbEnabled(msg.arg1 == 1);
50902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    break;
510f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood                case MSG_SET_CURRENT_FUNCTION:
511f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood                    String function = (String)msg.obj;
512f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood                    boolean makeDefault = (msg.arg1 == 1);
51368736cbf938935f7d7e1eb2b3f9ec911fcb0da72Mike Lockwood                    setEnabledFunctions(function, makeDefault);
51402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    break;
51502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                case MSG_SYSTEM_READY:
516d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    updateUsbNotification();
517d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    updateAdbNotification();
51802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    updateUsbState();
519d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood                    break;
520d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood                case MSG_BOOT_COMPLETED:
521d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood                    mBootCompleted = true;
522d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood                    if (mCurrentAccessory != null) {
52302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                        mSettingsManager.accessoryAttached(mCurrentAccessory);
52402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    }
52502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood                    break;
52646d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
52746d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
52846d0adf8256a42416584765625852b6e48497c90Mike Lockwood
52902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        public UsbAccessory getCurrentAccessory() {
53002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            return mCurrentAccessory;
53102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        }
53202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
533d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood        private void updateUsbNotification() {
534d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood            if (mNotificationManager == null || !mUseUsbNotification) return;
535a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood            int id = NOTIFICATION_NONE;
536a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood            Resources r = mContext.getResources();
537a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood            CharSequence title = null;
538d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood            if (mConnected) {
539d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) {
540d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    title = r.getText(
541d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                        com.android.internal.R.string.usb_mtp_notification_title);
542d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    id = NOTIFICATION_MTP;
543d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) {
544d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    title = r.getText(
545d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                        com.android.internal.R.string.usb_ptp_notification_title);
546d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    id = NOTIFICATION_PTP;
547d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                } else if (containsFunction(mCurrentFunctions,
548d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                        UsbManager.USB_FUNCTION_MASS_STORAGE)) {
549d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    title = r.getText(
550d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                        com.android.internal.R.string.usb_cd_installer_notification_title);
551d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    id = NOTIFICATION_INSTALLER;
5526e680dea3bc9e2d4ba1a09f428c303cd2a59c051Mike Lockwood                } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) {
5536e680dea3bc9e2d4ba1a09f428c303cd2a59c051Mike Lockwood                    title = r.getText(
5546e680dea3bc9e2d4ba1a09f428c303cd2a59c051Mike Lockwood                        com.android.internal.R.string.usb_accessory_notification_title);
5556e680dea3bc9e2d4ba1a09f428c303cd2a59c051Mike Lockwood                    id = NOTIFICATION_ACCESSORY;
556d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                } else {
557a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood                    // There is a different notification for USB tethering so we don't need one here
558a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood                    if (!containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) {
559a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood                        Slog.e(TAG, "No known USB function in updateUsbNotification");
560d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    }
561d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                }
562a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood            }
563a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood            if (id != mUsbNotificationId) {
564a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood                // clear notification if title needs changing
565a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood                if (mUsbNotificationId != NOTIFICATION_NONE) {
566a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood                    mNotificationManager.cancel(mUsbNotificationId);
567a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood                    mUsbNotificationId = NOTIFICATION_NONE;
568a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood                }
569a5010431bfcdff88ac9d96e68d8308071c13472bMike Lockwood                if (id != NOTIFICATION_NONE) {
570d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    CharSequence message = r.getText(
571d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                            com.android.internal.R.string.usb_notification_message);
572d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood
573d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    Notification notification = new Notification();
574d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
575d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.when = 0;
576d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.flags = Notification.FLAG_ONGOING_EVENT;
577d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.tickerText = title;
578d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.defaults = 0; // please be quiet
579d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.sound = null;
580d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.vibrate = null;
581d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood
582c50bff85281fa9661310465e88fd62890ccc9240Mike Lockwood                    Intent intent = new Intent(
583c50bff85281fa9661310465e88fd62890ccc9240Mike Lockwood                            Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
584d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
585d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                            Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
586c50bff85281fa9661310465e88fd62890ccc9240Mike Lockwood                    intent.setComponent(new ComponentName("com.android.settings",
587c50bff85281fa9661310465e88fd62890ccc9240Mike Lockwood                            "com.android.settings.UsbSettings"));
588d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    PendingIntent pi = PendingIntent.getActivity(mContext, 0,
589d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                            intent, 0);
590d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.setLatestEventInfo(mContext, title, message, pi);
591d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    mNotificationManager.notify(id, notification);
592d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    mUsbNotificationId = id;
593d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                }
594d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood            }
595d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood        }
596d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood
597d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood        private void updateAdbNotification() {
598d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood            if (mNotificationManager == null) return;
599d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood            if (mAdbEnabled && mConnected) {
600d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
601d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood
602d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                if (!mAdbNotificationShown) {
603d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    Resources r = mContext.getResources();
604d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    CharSequence title = r.getText(
605d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                            com.android.internal.R.string.adb_active_notification_title);
606d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    CharSequence message = r.getText(
607d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                            com.android.internal.R.string.adb_active_notification_message);
608d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood
609d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    Notification notification = new Notification();
610d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.icon = com.android.internal.R.drawable.stat_sys_adb;
611d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.when = 0;
612d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.flags = Notification.FLAG_ONGOING_EVENT;
613d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.tickerText = title;
614d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.defaults = 0; // please be quiet
615d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.sound = null;
616d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.vibrate = null;
617d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood
618d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    Intent intent = new Intent(
619d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                            Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
620d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
621d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                            Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
622d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    intent.setComponent(new ComponentName("com.android.settings",
623d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                            "com.android.settings.DevelopmentSettings"));
624d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    PendingIntent pi = PendingIntent.getActivity(mContext, 0,
625d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                            intent, 0);
626d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    notification.setLatestEventInfo(mContext, title, message, pi);
627d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    mAdbNotificationShown = true;
628d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                    mNotificationManager.notify(NOTIFICATION_ADB, notification);
629d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                }
630d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood            } else if (mAdbNotificationShown) {
631d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                mAdbNotificationShown = false;
632d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood                mNotificationManager.cancel(NOTIFICATION_ADB);
633d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood            }
634d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood        }
635d8404d2fdd7036435748548a6791063fb6d6c909Mike Lockwood
63602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        public void dump(FileDescriptor fd, PrintWriter pw) {
63702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            pw.println("  USB Device State:");
63802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            pw.println("    Current Functions: " + mCurrentFunctions);
63902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            pw.println("    Default Functions: " + mDefaultFunctions);
64002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            pw.println("    mConnected: " + mConnected);
64102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            pw.println("    mConfigured: " + mConfigured);
64202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            pw.println("    mCurrentAccessory: " + mCurrentAccessory);
6436ea146c239f2468563b4e8766b446d14ae4a1ff5Mike Lockwood            try {
6446ea146c239f2468563b4e8766b446d14ae4a1ff5Mike Lockwood                pw.println("    Kernel state: "
6456ea146c239f2468563b4e8766b446d14ae4a1ff5Mike Lockwood                        + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
6466ea146c239f2468563b4e8766b446d14ae4a1ff5Mike Lockwood                pw.println("    Kernel function list: "
6476ea146c239f2468563b4e8766b446d14ae4a1ff5Mike Lockwood                        + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
6486ea146c239f2468563b4e8766b446d14ae4a1ff5Mike Lockwood                pw.println("    Mass storage backing file: "
6496ea146c239f2468563b4e8766b446d14ae4a1ff5Mike Lockwood                        + FileUtils.readTextFile(new File(MASS_STORAGE_FILE_PATH), 0, null).trim());
6506ea146c239f2468563b4e8766b446d14ae4a1ff5Mike Lockwood            } catch (IOException e) {
6516ea146c239f2468563b4e8766b446d14ae4a1ff5Mike Lockwood                pw.println("IOException: " + e);
6526ea146c239f2468563b4e8766b446d14ae4a1ff5Mike Lockwood            }
65302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        }
65446d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
65546d0adf8256a42416584765625852b6e48497c90Mike Lockwood
65602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    /* returns the currently attached USB accessory */
65746d0adf8256a42416584765625852b6e48497c90Mike Lockwood    public UsbAccessory getCurrentAccessory() {
65802e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        return mHandler.getCurrentAccessory();
65946d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
66046d0adf8256a42416584765625852b6e48497c90Mike Lockwood
66102e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    /* opens the currently attached USB accessory */
662abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
663abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood        UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
664abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood        if (currentAccessory == null) {
665abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood            throw new IllegalArgumentException("no accessory attached");
66646d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
667abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood        if (!currentAccessory.equals(accessory)) {
668abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood            String error = accessory.toString()
669abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood                    + " does not match current accessory "
670abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood                    + currentAccessory;
671abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood            throw new IllegalArgumentException(error);
672abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood        }
673abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood        mSettingsManager.checkPermission(accessory);
674abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood        return nativeOpenAccessory();
675abc4ac6d48c52bd8b69026441bf261e5c68c24f4Mike Lockwood    }
67602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood
677f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood    public void setCurrentFunction(String function, boolean makeDefault) {
678fdc0c2984d05e32954608f46514c4cbe3a5a9424Mike Lockwood        if (DEBUG) Slog.d(TAG, "setCurrentFunction(" + function + ") default: " + makeDefault);
679f59717ddb5ef324ee3fdb12b83e7d1b709793d28Mike Lockwood        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTION, function, makeDefault);
68002e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    }
68146d0adf8256a42416584765625852b6e48497c90Mike Lockwood
68202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    public void setMassStorageBackingFile(String path) {
68302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        if (path == null) path = "";
68402e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        try {
68502e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            FileUtils.stringToFile(MASS_STORAGE_FILE_PATH, path);
68602e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        } catch (IOException e) {
68702e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood           Slog.e(TAG, "failed to write to " + MASS_STORAGE_FILE_PATH);
68846d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
68902e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood    }
69046d0adf8256a42416584765625852b6e48497c90Mike Lockwood
69146d0adf8256a42416584765625852b6e48497c90Mike Lockwood    public void dump(FileDescriptor fd, PrintWriter pw) {
69202e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood        if (mHandler != null) {
69302e4569b5f126ca916a7473117ddd17d4f2ccbbbMike Lockwood            mHandler.dump(fd, pw);
69446d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
69546d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
69646d0adf8256a42416584765625852b6e48497c90Mike Lockwood
69746d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private native String[] nativeGetAccessoryStrings();
69846d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private native ParcelFileDescriptor nativeOpenAccessory();
699d462ecf8f82076d21c85bdeeefbd16a1a91d2805Mike Lockwood    private native boolean nativeIsStartRequested();
70046d0adf8256a42416584765625852b6e48497c90Mike Lockwood}
701