1abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood/*
2abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood * Copyright (C) 2010 The Android Open Source Project
3abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood *
4abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
5abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood * you may not use this file except in compliance with the License.
6abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood * You may obtain a copy of the License at
7abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood *
8abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
9abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood *
10abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood * Unless required by applicable law or agreed to in writing, software
11abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
12abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood * See the License for the specific language governing permissions and
14abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood * limitations under the License.
15abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood */
16abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood
17abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwoodpackage com.android.providers.media;
18abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood
198efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkeyimport android.app.ActivityManager;
20abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwoodimport android.app.Service;
21abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwoodimport android.content.Intent;
226fcef4f5098c35a94cf0f17b6dd2b99149d2296cMike Lockwoodimport android.hardware.usb.UsbManager;
2390345783ad297da6059398cab174687de6f36a5bMike Lockwoodimport android.mtp.MtpDatabase;
2490345783ad297da6059398cab174687de6f36a5bMike Lockwoodimport android.mtp.MtpServer;
25d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwoodimport android.mtp.MtpStorage;
26abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwoodimport android.os.Environment;
27abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwoodimport android.os.IBinder;
288efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkeyimport android.os.UserHandle;
29d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwoodimport android.os.storage.StorageEventListener;
30d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwoodimport android.os.storage.StorageManager;
31c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwoodimport android.os.storage.StorageVolume;
32abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwoodimport android.util.Log;
33abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood
341e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwoodimport java.io.File;
35d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwoodimport java.util.HashMap;
36d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood
37d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwoodpublic class MtpService extends Service {
38abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood    private static final String TAG = "MtpService";
391469c78b58e40d0400487e61078b1297899d8956Nick Kralevich    private static final boolean LOGD = false;
40abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood
411e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood    // We restrict PTP to these subdirectories
421e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood    private static final String[] PTP_DIRECTORIES = new String[] {
431e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood        Environment.DIRECTORY_DCIM,
441e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood        Environment.DIRECTORY_PICTURES,
451e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood    };
461e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood
471e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood    private void addStorageDevicesLocked() {
481e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood        if (mPtpMode) {
491e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood            // In PTP mode we support only primary storage
50395ad2597601ccf285cfe679c7263a1b1feee231Jeff Sharkey            final StorageVolume primary = StorageManager.getPrimaryVolume(mVolumes);
5157b65f10aaafc4bf42a0fa59eb2bbe6c8371c2e6Jeff Sharkey            final String path = primary.getPath();
528d13ca8552efd8292099a7bf5a30c0e0d18a60e7Chuanxiao Dong            if (path != null) {
538d13ca8552efd8292099a7bf5a30c0e0d18a60e7Chuanxiao Dong                String state = mStorageManager.getVolumeState(path);
548d13ca8552efd8292099a7bf5a30c0e0d18a60e7Chuanxiao Dong                if (Environment.MEDIA_MOUNTED.equals(state)) {
5557b65f10aaafc4bf42a0fa59eb2bbe6c8371c2e6Jeff Sharkey                    addStorageLocked(mVolumeMap.get(path));
568d13ca8552efd8292099a7bf5a30c0e0d18a60e7Chuanxiao Dong                }
578d13ca8552efd8292099a7bf5a30c0e0d18a60e7Chuanxiao Dong            }
581e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood        } else {
5955bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood            for (StorageVolume volume : mVolumeMap.values()) {
6055bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood                addStorageLocked(volume);
611e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood            }
621e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood        }
631e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood    }
641e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood
65d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood    private final StorageEventListener mStorageEventListener = new StorageEventListener() {
668efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey        @Override
67d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        public void onStorageStateChanged(String path, String oldState, String newState) {
68d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood            synchronized (mBinder) {
69d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood                Log.d(TAG, "onStorageStateChanged " + path + " " + oldState + " -> " + newState);
70d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood                if (Environment.MEDIA_MOUNTED.equals(newState)) {
71d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood                    volumeMountedLocked(path);
72d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood                } else if (Environment.MEDIA_MOUNTED.equals(oldState)) {
7355bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood                    StorageVolume volume = mVolumeMap.remove(path);
7455bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood                    if (volume != null) {
7555bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood                        removeStorageLocked(volume);
76868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood                    }
77868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood                }
78868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood            }
79868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood        }
80868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood    };
81868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood
82d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood    private MtpDatabase mDatabase;
83abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood    private MtpServer mServer;
84d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood    private StorageManager mStorageManager;
858efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey    /** Flag indicating if MTP is disabled due to keyguard */
868efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey    private boolean mMtpDisabled;
871469c78b58e40d0400487e61078b1297899d8956Nick Kralevich    private boolean mUnlocked;
881e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood    private boolean mPtpMode;
8955bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood    private final HashMap<String, StorageVolume> mVolumeMap = new HashMap<String, StorageVolume>();
90d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood    private final HashMap<String, MtpStorage> mStorageMap = new HashMap<String, MtpStorage>();
91c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood    private StorageVolume[] mVolumes;
92685aac2d437ef229f81b167ffa1dae95fe2d1a97Mike Lockwood
93685aac2d437ef229f81b167ffa1dae95fe2d1a97Mike Lockwood    @Override
94685aac2d437ef229f81b167ffa1dae95fe2d1a97Mike Lockwood    public void onCreate() {
958efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey        mStorageManager = StorageManager.from(this);
96d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        synchronized (mBinder) {
978efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            updateDisabledStateLocked();
98d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood            mStorageManager.registerListener(mStorageEventListener);
99c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood            StorageVolume[] volumes = mStorageManager.getVolumeList();
100c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood            mVolumes = volumes;
101d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood            for (int i = 0; i < volumes.length; i++) {
102c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood                String path = volumes[i].getPath();
103d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood                String state = mStorageManager.getVolumeState(path);
104d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood                if (Environment.MEDIA_MOUNTED.equals(state)) {
1058efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey                    volumeMountedLocked(path);
106d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood                }
107d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood            }
108d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        }
109685aac2d437ef229f81b167ffa1dae95fe2d1a97Mike Lockwood    }
110abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood
111abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood    @Override
112819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood    public int onStartCommand(Intent intent, int flags, int startId) {
1131469c78b58e40d0400487e61078b1297899d8956Nick Kralevich        mUnlocked = intent.getBooleanExtra(UsbManager.USB_DATA_UNLOCKED, false);
1141469c78b58e40d0400487e61078b1297899d8956Nick Kralevich        if (LOGD) { Log.d(TAG, "onStartCommand intent=" + intent + " mUnlocked=" + mUnlocked); }
115abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood        synchronized (mBinder) {
1168efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            updateDisabledStateLocked();
1178efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            mPtpMode = (intent == null ? false
1188efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey                    : intent.getBooleanExtra(UsbManager.USB_FUNCTION_PTP, false));
1198efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            String[] subdirs = null;
1208efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            if (mPtpMode) {
1218efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey                int count = PTP_DIRECTORIES.length;
1228efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey                subdirs = new String[count];
1238efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey                for (int i = 0; i < count; i++) {
1248efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey                    File file =
1258efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey                            Environment.getExternalStoragePublicDirectory(PTP_DIRECTORIES[i]);
1268efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey                    // make sure this directory exists
1278efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey                    file.mkdirs();
1288efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey                    subdirs[i] = file.getPath();
1291e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood                }
130abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood            }
1318efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            final StorageVolume primary = StorageManager.getPrimaryVolume(mVolumes);
1321e45d525d1e521a0b1d425d53f1cda773fd203d3Marco Nelissen            if (mDatabase != null) {
1331e45d525d1e521a0b1d425d53f1cda773fd203d3Marco Nelissen                mDatabase.setServer(null);
1341e45d525d1e521a0b1d425d53f1cda773fd203d3Marco Nelissen            }
1359aecbd92265fe74a29d47866abbb233c1454effcDaichi Hirono            manageServiceLocked(primary, subdirs);
136abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood        }
137819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood
138bc640a0889da34c67b1eb298fe9de04609fd78b6Jeff Sharkey        return START_REDELIVER_INTENT;
139abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood    }
140abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood
1418efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey    private void updateDisabledStateLocked() {
1428efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey        final boolean isCurrentUser = UserHandle.myUserId() == ActivityManager.getCurrentUser();
1431469c78b58e40d0400487e61078b1297899d8956Nick Kralevich        mMtpDisabled = !mUnlocked || !isCurrentUser;
1448efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey        if (LOGD) {
1458efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            Log.d(TAG, "updating state; isCurrentUser=" + isCurrentUser + ", mMtpLocked="
1468efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey                    + mMtpDisabled);
1478efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey        }
1488efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey    }
1498efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey
1508efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey    /**
1518efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey     * Manage {@link #mServer}, creating only when running as the current user.
1528efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey     */
1539aecbd92265fe74a29d47866abbb233c1454effcDaichi Hirono    private void manageServiceLocked(StorageVolume primary, String[] subdirs) {
1548efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey        final boolean isCurrentUser = UserHandle.myUserId() == ActivityManager.getCurrentUser();
1558efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey        if (mServer == null && isCurrentUser) {
1568efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            Log.d(TAG, "starting MTP server in " + (mPtpMode ? "PTP mode" : "MTP mode"));
1579aecbd92265fe74a29d47866abbb233c1454effcDaichi Hirono            mDatabase = new MtpDatabase(this, MediaProvider.EXTERNAL_VOLUME,
1589aecbd92265fe74a29d47866abbb233c1454effcDaichi Hirono                    primary.getPath(), subdirs);
1598efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            mServer = new MtpServer(mDatabase, mPtpMode);
160bcbcb91c4cac69658faebd6e45ca6490d944778aMike Lockwood            mDatabase.setServer(mServer);
1618efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            if (!mMtpDisabled) {
1628efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey                addStorageDevicesLocked();
1638efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            }
1648efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            mServer.start();
1658efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey        } else if (mServer != null && !isCurrentUser) {
1668efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            Log.d(TAG, "no longer current user; shutting down MTP server");
1678efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            // Internally, kernel will close our FD, and server thread will
1688efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            // handle cleanup.
1698efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey            mServer = null;
170bcbcb91c4cac69658faebd6e45ca6490d944778aMike Lockwood            mDatabase.setServer(null);
1718efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey        }
1728efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey    }
1738efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey
174819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood    @Override
1758efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey    public void onDestroy() {
176d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        mStorageManager.unregisterListener(mStorageEventListener);
1771e45d525d1e521a0b1d425d53f1cda773fd203d3Marco Nelissen        if (mDatabase != null) {
1781e45d525d1e521a0b1d425d53f1cda773fd203d3Marco Nelissen            mDatabase.setServer(null);
1791e45d525d1e521a0b1d425d53f1cda773fd203d3Marco Nelissen        }
180abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood    }
181abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood
182d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood    private final IMtpService.Stub mBinder =
183d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood            new IMtpService.Stub() {
184d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood        public void sendObjectAdded(int objectHandle) {
1853d8bf05677c11764474df82ec5dc912c9e746b0aMike Lockwood            synchronized (mBinder) {
186d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood                if (mServer != null) {
187d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood                    mServer.sendObjectAdded(objectHandle);
188d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood                }
189d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood            }
190d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood        }
191d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood
192d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood        public void sendObjectRemoved(int objectHandle) {
1933d8bf05677c11764474df82ec5dc912c9e746b0aMike Lockwood            synchronized (mBinder) {
194d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood                if (mServer != null) {
195d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood                    mServer.sendObjectRemoved(objectHandle);
196d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood                }
197d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood            }
198d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood        }
199d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood    };
200d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood
201abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood    @Override
2028efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey    public IBinder onBind(Intent intent) {
203d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood        return mBinder;
204abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood    }
205d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood
206d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood    private void volumeMountedLocked(String path) {
207c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood        for (int i = 0; i < mVolumes.length; i++) {
208c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood            StorageVolume volume = mVolumes[i];
209c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood            if (volume.getPath().equals(path)) {
21055bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood                mVolumeMap.put(path, volume);
211d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood                if (!mMtpDisabled) {
2121e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood                    // In PTP mode we support only primary storage
213395ad2597601ccf285cfe679c7263a1b1feee231Jeff Sharkey                    if (volume.isPrimary() || !mPtpMode) {
21455bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood                        addStorageLocked(volume);
2151e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood                    }
216d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood                }
217d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood                break;
218d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood            }
219d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        }
220d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood    }
221d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood
22255bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood    private void addStorageLocked(StorageVolume volume) {
2239681e238cd39c3cfbbd63d47d26a1d9bff9f09e5Fabrice Di Meglio        MtpStorage storage = new MtpStorage(volume, getApplicationContext());
22440fef25a59cc7a36b99857b756befc36e6996845Jeff Sharkey        mStorageMap.put(storage.getPath(), storage);
22540fef25a59cc7a36b99857b756befc36e6996845Jeff Sharkey
22640fef25a59cc7a36b99857b756befc36e6996845Jeff Sharkey        if (storage.getStorageId() == StorageVolume.STORAGE_ID_INVALID) {
22740fef25a59cc7a36b99857b756befc36e6996845Jeff Sharkey            Log.w(TAG, "Ignoring volume with invalid MTP storage ID: " + storage);
22840fef25a59cc7a36b99857b756befc36e6996845Jeff Sharkey            return;
22940fef25a59cc7a36b99857b756befc36e6996845Jeff Sharkey        } else {
23040fef25a59cc7a36b99857b756befc36e6996845Jeff Sharkey            Log.d(TAG, "Adding MTP storage 0x" + Integer.toHexString(storage.getStorageId())
23140fef25a59cc7a36b99857b756befc36e6996845Jeff Sharkey                    + " at " + storage.getPath());
23240fef25a59cc7a36b99857b756befc36e6996845Jeff Sharkey        }
2338efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey
234d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        if (mDatabase != null) {
235d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood            mDatabase.addStorage(storage);
236d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        }
237d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        if (mServer != null) {
238d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood            mServer.addStorage(storage);
239d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        }
240d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood    }
241d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood
24255bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood    private void removeStorageLocked(StorageVolume volume) {
24355bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood        MtpStorage storage = mStorageMap.remove(volume.getPath());
24455bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood        if (storage == null) {
24540fef25a59cc7a36b99857b756befc36e6996845Jeff Sharkey            Log.e(TAG, "Missing MtpStorage for " + volume.getPath());
24655bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood            return;
24755bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood        }
24855bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood
24940fef25a59cc7a36b99857b756befc36e6996845Jeff Sharkey        Log.d(TAG, "Removing MTP storage " + Integer.toHexString(storage.getStorageId()) + " at "
25040fef25a59cc7a36b99857b756befc36e6996845Jeff Sharkey                + storage.getPath());
251d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        if (mDatabase != null) {
252d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood            mDatabase.removeStorage(storage);
253d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        }
254d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        if (mServer != null) {
255d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood            mServer.removeStorage(storage);
256d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood        }
257d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood    }
258abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood}
259