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; 20868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwoodimport android.app.KeyguardManager; 21abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwoodimport android.app.Service; 22868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwoodimport android.content.BroadcastReceiver; 23abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwoodimport android.content.Context; 24abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwoodimport android.content.Intent; 25abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwoodimport android.content.IntentFilter; 266fcef4f5098c35a94cf0f17b6dd2b99149d2296cMike Lockwoodimport android.hardware.usb.UsbManager; 2790345783ad297da6059398cab174687de6f36a5bMike Lockwoodimport android.mtp.MtpDatabase; 2890345783ad297da6059398cab174687de6f36a5bMike Lockwoodimport android.mtp.MtpServer; 29d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwoodimport android.mtp.MtpStorage; 30abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwoodimport android.os.Environment; 31abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwoodimport android.os.IBinder; 328efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkeyimport android.os.UserHandle; 33d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwoodimport android.os.storage.StorageEventListener; 34d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwoodimport android.os.storage.StorageManager; 35c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwoodimport android.os.storage.StorageVolume; 36abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwoodimport android.util.Log; 37abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood 381e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwoodimport java.io.File; 39d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwoodimport java.util.HashMap; 40d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood 41d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwoodpublic class MtpService extends Service { 42abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood private static final String TAG = "MtpService"; 438efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey private static final boolean LOGD = true; 44abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood 451e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood // We restrict PTP to these subdirectories 461e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood private static final String[] PTP_DIRECTORIES = new String[] { 471e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood Environment.DIRECTORY_DCIM, 481e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood Environment.DIRECTORY_PICTURES, 491e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood }; 501e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood 511e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood private void addStorageDevicesLocked() { 521e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood if (mPtpMode) { 531e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood // In PTP mode we support only primary storage 54395ad2597601ccf285cfe679c7263a1b1feee231Jeff Sharkey final StorageVolume primary = StorageManager.getPrimaryVolume(mVolumes); 5557b65f10aaafc4bf42a0fa59eb2bbe6c8371c2e6Jeff Sharkey final String path = primary.getPath(); 568d13ca8552efd8292099a7bf5a30c0e0d18a60e7Chuanxiao Dong if (path != null) { 578d13ca8552efd8292099a7bf5a30c0e0d18a60e7Chuanxiao Dong String state = mStorageManager.getVolumeState(path); 588d13ca8552efd8292099a7bf5a30c0e0d18a60e7Chuanxiao Dong if (Environment.MEDIA_MOUNTED.equals(state)) { 5957b65f10aaafc4bf42a0fa59eb2bbe6c8371c2e6Jeff Sharkey addStorageLocked(mVolumeMap.get(path)); 608d13ca8552efd8292099a7bf5a30c0e0d18a60e7Chuanxiao Dong } 618d13ca8552efd8292099a7bf5a30c0e0d18a60e7Chuanxiao Dong } 621e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood } else { 6355bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood for (StorageVolume volume : mVolumeMap.values()) { 6455bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood addStorageLocked(volume); 651e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood } 661e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood } 671e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood } 681e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood 69868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 70868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood @Override 71868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood public void onReceive(Context context, Intent intent) { 72868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood final String action = intent.getAction(); 73868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood if (Intent.ACTION_USER_PRESENT.equals(action)) { 74e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen // If the media scanner is running, it may currently be calling 75e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen // sendObjectAdded/Removed, which also synchronizes on mBinder 76e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen // (and in addition to that, all the native MtpServer methods 77e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen // lock the same Mutex). If it happens to be in an mtp device 78e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen // write(), it may block for some time, so process this broadcast 79e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen // in a thread. 80e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen new Thread(new Runnable() { 81e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen @Override 82e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen public void run() { 83e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen synchronized (mBinder) { 84e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen // Unhide the storage units when the user has unlocked the lockscreen 85e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen if (mMtpDisabled) { 86e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen addStorageDevicesLocked(); 87e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen mMtpDisabled = false; 88e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen } 89e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen } 90e89c3f8afe178cf31457917e13b017e8ff76dc52Marco Nelissen }}, "addStorageDevices").start(); 91d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 92d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 93d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood }; 94d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood 95d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood private final StorageEventListener mStorageEventListener = new StorageEventListener() { 968efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey @Override 97d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood public void onStorageStateChanged(String path, String oldState, String newState) { 98d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood synchronized (mBinder) { 99d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood Log.d(TAG, "onStorageStateChanged " + path + " " + oldState + " -> " + newState); 100d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood if (Environment.MEDIA_MOUNTED.equals(newState)) { 101d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood volumeMountedLocked(path); 102d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } else if (Environment.MEDIA_MOUNTED.equals(oldState)) { 10355bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood StorageVolume volume = mVolumeMap.remove(path); 10455bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood if (volume != null) { 10555bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood removeStorageLocked(volume); 106868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood } 107868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood } 108868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood } 109868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood } 110868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood }; 111868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood 112d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood private MtpDatabase mDatabase; 113abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood private MtpServer mServer; 114d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood private StorageManager mStorageManager; 1158efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey /** Flag indicating if MTP is disabled due to keyguard */ 1168efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey private boolean mMtpDisabled; 1171e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood private boolean mPtpMode; 11855bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood private final HashMap<String, StorageVolume> mVolumeMap = new HashMap<String, StorageVolume>(); 119d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood private final HashMap<String, MtpStorage> mStorageMap = new HashMap<String, MtpStorage>(); 120c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood private StorageVolume[] mVolumes; 121685aac2d437ef229f81b167ffa1dae95fe2d1a97Mike Lockwood 122685aac2d437ef229f81b167ffa1dae95fe2d1a97Mike Lockwood @Override 123685aac2d437ef229f81b167ffa1dae95fe2d1a97Mike Lockwood public void onCreate() { 124868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_PRESENT)); 125d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood 1268efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey mStorageManager = StorageManager.from(this); 127d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood synchronized (mBinder) { 1288efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey updateDisabledStateLocked(); 129d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood mStorageManager.registerListener(mStorageEventListener); 130c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood StorageVolume[] volumes = mStorageManager.getVolumeList(); 131c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood mVolumes = volumes; 132d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood for (int i = 0; i < volumes.length; i++) { 133c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood String path = volumes[i].getPath(); 134d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood String state = mStorageManager.getVolumeState(path); 135d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood if (Environment.MEDIA_MOUNTED.equals(state)) { 1368efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey volumeMountedLocked(path); 137d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 138d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 139d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 140685aac2d437ef229f81b167ffa1dae95fe2d1a97Mike Lockwood } 141abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood 142abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood @Override 143819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood public int onStartCommand(Intent intent, int flags, int startId) { 144abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood synchronized (mBinder) { 1458efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey updateDisabledStateLocked(); 1468efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey mPtpMode = (intent == null ? false 1478efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey : intent.getBooleanExtra(UsbManager.USB_FUNCTION_PTP, false)); 1488efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey String[] subdirs = null; 1498efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey if (mPtpMode) { 1508efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey int count = PTP_DIRECTORIES.length; 1518efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey subdirs = new String[count]; 1528efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey for (int i = 0; i < count; i++) { 1538efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey File file = 1548efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey Environment.getExternalStoragePublicDirectory(PTP_DIRECTORIES[i]); 1558efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey // make sure this directory exists 1568efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey file.mkdirs(); 1578efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey subdirs[i] = file.getPath(); 1581e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood } 159abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood } 1608efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey final StorageVolume primary = StorageManager.getPrimaryVolume(mVolumes); 1611e45d525d1e521a0b1d425d53f1cda773fd203d3Marco Nelissen if (mDatabase != null) { 1621e45d525d1e521a0b1d425d53f1cda773fd203d3Marco Nelissen mDatabase.setServer(null); 1631e45d525d1e521a0b1d425d53f1cda773fd203d3Marco Nelissen } 1648efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey mDatabase = new MtpDatabase(this, MediaProvider.EXTERNAL_VOLUME, 1658efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey primary.getPath(), subdirs); 1668efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey manageServiceLocked(); 167abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood } 168819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood 169819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood return START_STICKY; 170abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood } 171abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood 1728efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey private void updateDisabledStateLocked() { 1738efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey final boolean isCurrentUser = UserHandle.myUserId() == ActivityManager.getCurrentUser(); 1748efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey final KeyguardManager keyguardManager = (KeyguardManager) getSystemService( 1758efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey Context.KEYGUARD_SERVICE); 1768efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey mMtpDisabled = (keyguardManager.isKeyguardLocked() && keyguardManager.isKeyguardSecure()) 1778efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey || !isCurrentUser; 1788efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey if (LOGD) { 1798efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey Log.d(TAG, "updating state; isCurrentUser=" + isCurrentUser + ", mMtpLocked=" 1808efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey + mMtpDisabled); 1818efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey } 1828efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey } 1838efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey 1848efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey /** 1858efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey * Manage {@link #mServer}, creating only when running as the current user. 1868efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey */ 1878efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey private void manageServiceLocked() { 1888efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey final boolean isCurrentUser = UserHandle.myUserId() == ActivityManager.getCurrentUser(); 1898efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey if (mServer == null && isCurrentUser) { 1908efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey Log.d(TAG, "starting MTP server in " + (mPtpMode ? "PTP mode" : "MTP mode")); 1918efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey mServer = new MtpServer(mDatabase, mPtpMode); 192bcbcb91c4cac69658faebd6e45ca6490d944778aMike Lockwood mDatabase.setServer(mServer); 1938efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey if (!mMtpDisabled) { 1948efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey addStorageDevicesLocked(); 1958efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey } 1968efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey mServer.start(); 1978efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey } else if (mServer != null && !isCurrentUser) { 1988efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey Log.d(TAG, "no longer current user; shutting down MTP server"); 1998efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey // Internally, kernel will close our FD, and server thread will 2008efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey // handle cleanup. 2018efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey mServer = null; 202bcbcb91c4cac69658faebd6e45ca6490d944778aMike Lockwood mDatabase.setServer(null); 2038efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey } 2048efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey } 2058efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey 206819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood @Override 2078efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey public void onDestroy() { 208868c8a91b9fe8aba9e3c1f17514c3aa1022307d5Mike Lockwood unregisterReceiver(mReceiver); 209d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood mStorageManager.unregisterListener(mStorageEventListener); 2101e45d525d1e521a0b1d425d53f1cda773fd203d3Marco Nelissen if (mDatabase != null) { 2111e45d525d1e521a0b1d425d53f1cda773fd203d3Marco Nelissen mDatabase.setServer(null); 2121e45d525d1e521a0b1d425d53f1cda773fd203d3Marco Nelissen } 213abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood } 214abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood 215d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private final IMtpService.Stub mBinder = 216d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood new IMtpService.Stub() { 217d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void sendObjectAdded(int objectHandle) { 2183d8bf05677c11764474df82ec5dc912c9e746b0aMike Lockwood synchronized (mBinder) { 219d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mServer != null) { 220d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mServer.sendObjectAdded(objectHandle); 221d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 222d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 223d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 224d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 225d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void sendObjectRemoved(int objectHandle) { 2263d8bf05677c11764474df82ec5dc912c9e746b0aMike Lockwood synchronized (mBinder) { 227d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mServer != null) { 228d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mServer.sendObjectRemoved(objectHandle); 229d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 230d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 231d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 232d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood }; 233d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 234abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood @Override 2358efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey public IBinder onBind(Intent intent) { 236d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood return mBinder; 237abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood } 238d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood 239d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood private void volumeMountedLocked(String path) { 240c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood for (int i = 0; i < mVolumes.length; i++) { 241c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood StorageVolume volume = mVolumes[i]; 242c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood if (volume.getPath().equals(path)) { 24355bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood mVolumeMap.put(path, volume); 244d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood if (!mMtpDisabled) { 2451e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood // In PTP mode we support only primary storage 246395ad2597601ccf285cfe679c7263a1b1feee231Jeff Sharkey if (volume.isPrimary() || !mPtpMode) { 24755bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood addStorageLocked(volume); 2481e950b8090d90bbf92e528a974ecb8c5c48dff84Mike Lockwood } 249d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 250d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood break; 251d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 252d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 253d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 254d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood 25555bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood private void addStorageLocked(StorageVolume volume) { 2569681e238cd39c3cfbbd63d47d26a1d9bff9f09e5Fabrice Di Meglio MtpStorage storage = new MtpStorage(volume, getApplicationContext()); 25755bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood String path = storage.getPath(); 25855bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood mStorageMap.put(path, storage); 2598efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey 2608efd65fe64c7978534bb549b2329068a2f8c5075Jeff Sharkey Log.d(TAG, "addStorageLocked " + storage.getStorageId() + " " + path); 261d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood if (mDatabase != null) { 262d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood mDatabase.addStorage(storage); 263d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 264d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood if (mServer != null) { 265d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood mServer.addStorage(storage); 266d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 267d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 268d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood 26955bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood private void removeStorageLocked(StorageVolume volume) { 27055bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood MtpStorage storage = mStorageMap.remove(volume.getPath()); 27155bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood if (storage == null) { 27255bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood Log.e(TAG, "no MtpStorage for " + volume.getPath()); 27355bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood return; 27455bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood } 27555bf981b5231b0831a146ba67dc16d9f55c67154Mike Lockwood 276d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood Log.d(TAG, "removeStorageLocked " + storage.getStorageId() + " " + storage.getPath()); 277d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood if (mDatabase != null) { 278d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood mDatabase.removeStorage(storage); 279d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 280d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood if (mServer != null) { 281d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood mServer.removeStorage(storage); 282d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 283d3709e80446eb8abc3bb9c60db0d5c9473930611Mike Lockwood } 284abf8d09064cdc380d4996f5022d3a20eb4448ed1Mike Lockwood} 285