Setting卸载SD卡,可以格式化,卸载过程中还可以卸载问题


  587人阅读  评论(0)  收藏  举报
  分类:
 

问题是当我们再setting点击卸载SD卡的时候,这个时候“卸载SD卡”这一项会变成"正在卸载“并且变灰。但是很快又变亮了。而且卸载完后,还可以格式化。对于出现的这两个问题我们进行分析。


我们首先来看setting的代码

在Memory.java中实现了一个StorageEventListener :

[java]  view plain  copy
  1. StorageEventListener mStorageListener = new StorageEventListener() {  
  2.     @Override  
  3.     public void onStorageStateChanged(String path, String oldState, String newState) {  
  4.         Log.i(TAG, "Received storage state changed notification that " + path +  
  5.                 " changed state from " + oldState + " to " + newState);  
  6.         for (StorageVolumePreferenceCategory category : mCategories) {  
  7.             final StorageVolume volume = category.getStorageVolume();  
  8.             if (volume != null && path.equals(volume.getPath())) {  
  9.                 category.onStorageStateChanged();  
  10.                 break;  
  11.             }  
  12.         }  
  13.     }  
  14. };  

并且在MountService中注册了

[java]  view plain  copy
  1. @Override  
  2. public void onCreate(Bundle icicle) {  
  3.     super.onCreate(icicle);  
  4.   
  5.     final Context context = getActivity();  
  6.   
  7.     mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);  
  8.   
  9.     mStorageManager = StorageManager.from(context);  
  10.     mStorageManager.registerListener(mStorageListener);//注册listener  
  11.   
  12.     addPreferencesFromResource(R.xml.device_info_memory);  
  13.   
  14.     addCategory(StorageVolumePreferenceCategory.buildForInternal(context));  
  15.   
  16.     final StorageVolume[] storageVolumes = mStorageManager.getVolumeList();  
  17.     for (StorageVolume volume : storageVolumes) {  
  18.         if (!volume.isEmulated()) {  
  19.             addCategory(StorageVolumePreferenceCategory.buildForPhysical(context, volume));  
  20.         }  
  21.     }  
  22.   
  23.     setHasOptionsMenu(true);  
  24. }  

在在Memory.java中的StorageEventListener 调用了onStorageStateChanged函数,再来看看StorageVolumePreferenceCategory

[java]  view plain  copy
  1. public void onStorageStateChanged() {  
  2.     init();  
  3.     measure();  
  4. }  
[java]  view plain  copy
  1. private void measure() {  
  2.     mMeasure.invalidate();  
  3.     mMeasure.measure();  
  4. }  


再来看看mMeature,在StorageVolumePreferenceCategory构造函数里赋值

[java]  view plain  copy
  1. private StorageVolumePreferenceCategory(Context context, StorageVolume volume) {  
  2.     super(context);  
  3.   
  4.     mVolume = volume;  
  5.     mMeasure = StorageMeasurement.getInstance(context, volume);  
  6.   
  7.     mResources = context.getResources();  
  8.     mStorageManager = StorageManager.from(context);  
  9.     mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);  
  10.   
  11.     setTitle(volume != null ? volume.getDescription(context)  
  12.             : context.getText(R.string.internal_storage));  
  13. }  

而在StorageMeasurement中的measure函数如下

[java]  view plain  copy
  1. public void measure() {  
  2.     if (!mHandler.hasMessages(MeasurementHandler.MSG_MEASURE)) {  
  3.         mHandler.sendEmptyMessage(MeasurementHandler.MSG_MEASURE);  
  4.     }  
  5. }  
再来看看消息处理

[java]  view plain  copy
  1. @Override  
  2. public void handleMessage(Message msg) {  
  3.     switch (msg.what) {  
  4.         case MSG_MEASURE: {  
  5.             if (mCached != null) {  
  6.                 sendExactUpdate(mCached);  
  7.                 break;  
  8.             }  
  9.   
  10.             final Context context = (mContext != null) ? mContext.get() : null;  
  11.             if (context == null) {  
  12.                 return;  
  13.             }  
  14.   
  15.             synchronized (mLock) {  
  16.                 if (mBound) {  
  17.                     removeMessages(MSG_DISCONNECT);  
  18.                     sendMessage(obtainMessage(MSG_CONNECTED, mDefaultContainer));//继续发送消息  
  19.                 } else {  
  20.                     Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);  
  21.                     context.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,  
  22.                             UserHandle.OWNER);  
  23.                 }  
  24.             }  
  25.             break;  
  26.         }  
  27.         case MSG_CONNECTED: {  
  28.             IMediaContainerService imcs = (IMediaContainerService) msg.obj;  
  29.             measureApproximateStorage(imcs);//调用measureApproximateStorage  
  30.             measureExactStorage(imcs);  
  31.             break;  
  32.         }  

看看measureApproximateStorage函数

[java]  view plain  copy
  1. private void measureApproximateStorage(IMediaContainerService imcs) {  
  2.     final String path = mVolume != null ? mVolume.getPath()  
  3.             : Environment.getDataDirectory().getPath();  
  4.     try {  
  5.         final long[] stats = imcs.getFileSystemStats(path);  
  6.         mTotalSize = stats[0];  
  7.         mAvailSize = stats[1];  
  8.     } catch (Exception e) {  
  9.         Log.w(TAG, "Problem in container service", e);  
  10.     }  
  11.   
  12.     sendInternalApproximateUpdate();  
  13. }  

而在sendInternalApproximateUpdate函数中调用了receiver.updateApproximate

[java]  view plain  copy
  1. private void sendInternalApproximateUpdate() {  
  2.     MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null;  
  3.     if (receiver == null) {  
  4.         return;  
  5.     }  
  6.     receiver.updateApproximate(this, mTotalSize, mAvailSize);  
  7. }  

再来看看这个mReceiver

[java]  view plain  copy
  1. public void setReceiver(MeasurementReceiver receiver) {  
  2.     if (mReceiver == null || mReceiver.get() == null) {  
  3.         mReceiver = new WeakReference<MeasurementReceiver>(receiver);  
  4.     }  
  5. }  

StorageVolumePreferenceCategory中的mReceiver

[java]  view plain  copy
  1. private MeasurementReceiver mReceiver = new MeasurementReceiver() {  
  2.     @Override  
  3.     public void updateApproximate(StorageMeasurement meas, long totalSize, long availSize) {  
  4.         mUpdateHandler.obtainMessage(MSG_UI_UPDATE_APPROXIMATE, new long[] {  
  5.                 totalSize, availSize }).sendToTarget();  
  6.     }  
  7.   
  8.     @Override  
  9.     public void updateDetails(StorageMeasurement meas, MeasurementDetails details) {  
  10.         mUpdateHandler.obtainMessage(MSG_UI_UPDATE_DETAILS, details).sendToTarget();  
  11.     }  
  12. };  

在onResume的时候setReceiver

[java]  view plain  copy
  1. public void onResume() {  
  2.     mMeasure.setReceiver(mReceiver);  
  3.     measure();  
  4. }  

再看看消息处理:

[java]  view plain  copy
  1. private Handler mUpdateHandler = new Handler() {  
  2.     @Override  
  3.     public void handleMessage(Message msg) {  
  4.         switch (msg.what) {  
  5.             case MSG_UI_UPDATE_APPROXIMATE: {  
  6.                 final long[] size = (long[]) msg.obj;  
  7.                 updateApproximate(size[0], size[1]);  
  8.                 break;  
  9.             }  
  10.             case MSG_UI_UPDATE_DETAILS: {  
  11.                 final MeasurementDetails details = (MeasurementDetails) msg.obj;  
  12.                 updateDetails(details);  
  13.                 break;  
  14.             }  
  15.         }  
  16.     }  
  17. };  


再看看updateApproximate函数:

[java]  view plain  copy
  1. public void updateApproximate(long totalSize, long availSize) {  
  2.     mItemTotal.setSummary(formatSize(totalSize));  
  3.     mItemAvailable.setSummary(formatSize(availSize));  
  4.   
  5.     mTotalSize = totalSize;  
  6.   
  7.     final long usedSize = totalSize - availSize;  
  8.   
  9.     mUsageBarPreference.clear();  
  10.     mUsageBarPreference.addEntry(0, usedSize / (float) totalSize, android.graphics.Color.GRAY);  
  11.     mUsageBarPreference.commit();  
  12.   
  13.     updatePreferencesFromState();  
  14. }  

终于看到我们的主函数updatePreferencesFromState:

[java]  view plain  copy
  1. private void updatePreferencesFromState() {  
  2.        // Only update for physical volumes  
  3.        if (mVolume == nullreturn;  
  4.   
  5.        mMountTogglePreference.setEnabled(true);//先把卸载sd卡,安装sd卡置亮  
  6.   
  7.        final String state = mStorageManager.getVolumeState(mVolume.getPath());//获取volume的状态  
  8.   
  9.        if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {  
  10.            mItemAvailable.setTitle(R.string.memory_available_read_only);  
  11.        } else {  
  12.            mItemAvailable.setTitle(R.string.memory_available);  
  13.        }  
  14.   
  15.        if (Environment.MEDIA_MOUNTED.equals(state)//如果当前是挂载的置亮  
  16.                || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {  
  17.                mMountTogglePreference.setEnabled(true);  
  18.                mMountTogglePreference.setTitle(mResources.getString(R.string.sd_eject));  
  19.                mMountTogglePreference.setSummary(mResources.getString(R.string.sd_eject_summary));  
  20.                  
  21.                addPreference(mUsageBarPreference);  
  22.                addPreference(mItemTotal);  
  23.                addPreference(mItemAvailable);  
  24.        } else {  
  25.            if (Environment.MEDIA_UNMOUNTED.equals(state) || Environment.MEDIA_NOFS.equals(state)  
  26.                    || Environment.MEDIA_UNMOUNTABLE.equals(state)) {//如果是卸载,置亮;title变成安装SD卡  
  27.                mMountTogglePreference.setEnabled(true);  
  28.                mMountTogglePreference.setTitle(mResources.getString(R.string.sd_mount));  
  29.                mMountTogglePreference.setSummary(mResources.getString(R.string.sd_mount_summary));  
  30.            } else {//否则是没有SD卡,置灰  
  31.                mMountTogglePreference.setEnabled(false);  
  32.                mMountTogglePreference.setTitle(mResources.getString(R.string.sd_mount));  
  33.                mMountTogglePreference.setSummary(mResources.getString(R.string.sd_insert_summary));  
  34.            }  
  35.   
  36.            removePreference(mUsageBarPreference);  
  37.            removePreference(mItemTotal);  
  38.            removePreference(mItemAvailable);  
  39.        }  
  40.   
  41.        if (mUsbConnected && (UsbManager.USB_FUNCTION_MTP.equals(mUsbFunction) ||  
  42.                UsbManager.USB_FUNCTION_PTP.equals(mUsbFunction))) {//如果连usb,mtp  
  43.            mMountTogglePreference.setEnabled(false);//将sd卡那项置灰  
  44.            if (Environment.MEDIA_MOUNTED.equals(state)  
  45.                    || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {  
  46.                mMountTogglePreference.setSummary(  
  47.                        mResources.getString(R.string.mtp_ptp_mode_summary));  
  48.            }  
  49.   
  50.            if (mFormatPreference != null) {  
  51.                mFormatPreference.setEnabled(false);  
  52.                mFormatPreference.setSummary(mResources.getString(R.string.mtp_ptp_mode_summary));  
  53.            }  
  54.        } else if (mFormatPreference != null) {//最后格式化那项根据sd卡那项来置亮还是置灰。  
  55.            mFormatPreference.setEnabled(mMountTogglePreference.isEnabled());  
  56.            mFormatPreference.setSummary(mResources.getString(R.string.sd_format_summary));  
  57.        }  
  58.    }  


好,看了主函数后,问题来了。

首先当我们点击卸载sd卡后:

[java]  view plain  copy
  1. @Override  
  2. public Dialog onCreateDialog(int id) {  
  3.     switch (id) {  
  4.     case DLG_CONFIRM_UNMOUNT:  
  5.             return new AlertDialog.Builder(getActivity())  
  6.                 .setTitle(R.string.dlg_confirm_unmount_title)  
  7.                 .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {  
  8.                     public void onClick(DialogInterface dialog, int which) {  
  9.                         doUnmount();//点击后调用doUnmount  
  10.                     }})  
  11.                 .setNegativeButton(R.string.cancel, null)  
  12.                 .setMessage(R.string.dlg_confirm_unmount_text)  
  13.                 .create();  
  14.     case DLG_ERROR_UNMOUNT:  
  15.             return new AlertDialog.Builder(getActivity())  
  16.         .setTitle(R.string.dlg_error_unmount_title)  
  17.         .setNeutralButton(R.string.dlg_ok, null)  
  18.         .setMessage(R.string.dlg_error_unmount_text)  
  19.         .create();  
  20.     }  
  21.     return null;  
  22. }  
  23.   
  24. private void doUnmount() {  
  25.     // Present a toast here  
  26.     Toast.makeText(getActivity(), R.string.unmount_inform_text, Toast.LENGTH_SHORT).show();  
  27.     IMountService mountService = getMountService();  
  28.     try {  
  29.         sLastClickedMountToggle.setEnabled(false);//将卸载SD卡那项置灰  
  30.         sLastClickedMountToggle.setTitle(getString(R.string.sd_ejecting_title));//title改成"正在卸载"  
  31.         sLastClickedMountToggle.setSummary(getString(R.string.sd_ejecting_summary));  
  32.         mountService.unmountVolume(sClickedMountPoint, truefalse);  
  33.     } catch (RemoteException e) {  
  34.         // Informative dialog to user that unmount failed.  
  35.         showDialogInner(DLG_ERROR_UNMOUNT);  
  36.     }  
  37. }  


我们再来看看vold对卸载这个命令怎么处理:

[java]  view plain  copy
  1. int Volume::unmountVol(bool force, bool revert) {  
  2.     int i, rc;  
  3.   
  4.     int flags = getFlags();  
  5.     bool providesAsec = (flags & VOL_PROVIDES_ASEC) != 0;  
  6.   
  7.     if (getState() != Volume::State_Mounted) {  
  8.         SLOGE("Volume %s unmount request when not mounted", getLabel());  
  9.         errno = EINVAL;  
  10.         return UNMOUNT_NOT_MOUNTED_ERR;  
  11.     }  
  12.   
  13.     setState(Volume::State_Unmounting);//将状态置为unmounting,直接发送。setState中后面会直接发给MountService  
  14.     usleep(1000 * 1000); // Give the framework some time to react  
  15.   
  16.     char service[64];  
  17.     snprintf(service, 64"fuse_%s", getLabel());  
  18.     property_set("ctl.stop", service);  
  19.     /* Give it a chance to stop.  I wish we had a synchronous way to determine this... */  
  20.     sleep(1);  
  21.   
  22.     // TODO: determine failure mode if FUSE times out  
  23.   
  24.     if (providesAsec && doUnmount(Volume::SEC_ASECDIR_EXT, force) != 0) {  
  25.         SLOGE("Failed to unmount secure area on %s (%s)", getMountpoint(), strerror(errno));  
  26.         goto out_mounted;  
  27.     }  
  28.   
  29.     /* Now that the fuse daemon is dead, unmount it */  
  30.     if (doUnmount(getFuseMountpoint(), force) != 0) {  
  31.         SLOGE("Failed to unmount %s (%s)", getFuseMountpoint(), strerror(errno));  
  32.         goto fail_remount_secure;  
  33.     }  
  34.   
  35.     /* Unmount the real sd card */  
  36.     if (doUnmount(getMountpoint(), force) != 0) {  
  37.         SLOGE("Failed to unmount %s (%s)", getMountpoint(), strerror(errno));  
  38.         goto fail_remount_secure;  
  39.     }  
  40.   
  41.     SLOGI("%s unmounted successfully", getMountpoint());  
  42.   
  43.     /* If this is an encrypted volume, and we've been asked to undo 
  44.      * the crypto mapping, then revert the dm-crypt mapping, and revert 
  45.      * the device info to the original values. 
  46.      */  
  47.     if (revert && isDecrypted()) {  
  48.         cryptfs_revert_volume(getLabel());  
  49.         revertDeviceInfo();  
  50.         SLOGI("Encrypted volume %s reverted successfully", getMountpoint());  
  51.     }  
  52.   
  53.     setUuid(NULL);  
  54.     setUserLabel(NULL);  
  55.     setState(Volume::State_Idle);  
  56.     mCurrentlyMountedKdev = -1;  
  57.     return 0;  
  58.   
  59. fail_remount_secure:  
  60.     if (providesAsec && mountAsecExternal() != 0) {  
  61.         SLOGE("Failed to remount secure area (%s)", strerror(errno));  
  62.         goto out_nomedia;  
  63.     }  
  64.   
  65. out_mounted:  
  66.     setState(Volume::State_Mounted);  
  67.     return -1;  
  68.   
  69. out_nomedia:  
  70.     setState(Volume::State_NoMedia);  
  71.     return -1;  
  72. }  

MountService收到vold的消息,先调用onEvent函数,而unmounting属于VolumeStateChange

[java]  view plain  copy
  1. public boolean onEvent(int code, String raw, String[] cooked) {  
  2.     if (DEBUG_EVENTS) {  
  3.         StringBuilder builder = new StringBuilder();  
  4.         builder.append("onEvent::");  
  5.         builder.append(" raw= " + raw);  
  6.         if (cooked != null) {  
  7.             builder.append(" cooked = " );  
  8.             for (String str : cooked) {  
  9.                 builder.append(" " + str);  
  10.             }  
  11.         }  
  12.         Slog.i(TAG, builder.toString());  
  13.     }  
  14.     if (code == VoldResponseCode.VolumeStateChange) {  
  15.         /* 
  16.          * One of the volumes we're managing has changed state. 
  17.          * Format: "NNN Volume <label> <path> state changed 
  18.          * from <old_#> (<old_str>) to <new_#> (<new_str>)" 
  19.          */  
  20.         notifyVolumeStateChange(//调用notifyVolumeStateChange函数  
  21.                 cooked[2], cooked[3], Integer.parseInt(cooked[7]),  
  22.                         Integer.parseInt(cooked[10]));  
  23.     }  

再来看看notifyVolumeStateChange函数:

[java]  view plain  copy
  1. private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {  
  2.     final StorageVolume volume;  
  3.     final String state;  
  4.     synchronized (mVolumesLock) {  
  5.         volume = mVolumesByPath.get(path);  
  6.         state = getVolumeState(path);  
  7.     }  
  8.   
  9.     if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChange::" + state);  
  10.   
  11.     String action = null;  
  12.   
  13.     if (oldState == VolumeState.Shared && newState != oldState) {  
  14.         if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent");  
  15.         sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, volume, UserHandle.ALL);  
  16.     }  
  17.   
  18.     if (newState == VolumeState.Init) {  
  19.     } else if (newState == VolumeState.NoMedia) {  
  20.         // NoMedia is handled via Disk Remove events  
  21.     } else if (newState == VolumeState.Idle) {  
  22.         /* 
  23.          * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or 
  24.          * if we're in the process of enabling UMS 
  25.          */  
  26.         if (!state.equals(  
  27.                 Environment.MEDIA_BAD_REMOVAL) && !state.equals(  
  28.                         Environment.MEDIA_NOFS) && !state.equals(  
  29.                                 Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {  
  30.             if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable");  
  31.             updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);  
  32.             action = Intent.ACTION_MEDIA_UNMOUNTED;  
  33.         }  
  34.     } else if (newState == VolumeState.Pending) {  
  35.     } else if (newState == VolumeState.Checking) {  
  36.         if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking");  
  37.         updatePublicVolumeState(volume, Environment.MEDIA_CHECKING);  
  38.         action = Intent.ACTION_MEDIA_CHECKING;  
  39.     } else if (newState == VolumeState.Mounted) {  
  40.         if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");  
  41.         updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);  
  42.         action = Intent.ACTION_MEDIA_MOUNTED;  
  43.     } else if (newState == VolumeState.Unmounting) {//Unmounting的时候没有updatePublicVolumeState  
  44.         action = Intent.ACTION_MEDIA_EJECT;  
  45.     } else if (newState == VolumeState.Formatting) {  
  46.     } else if (newState == VolumeState.Shared) {  
  47.         if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted");  
  48.         /* Send the media unmounted event first */  
  49.         updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);  
  50.         sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);  
  51.   
  52.         if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared");  
  53.         updatePublicVolumeState(volume, Environment.MEDIA_SHARED);  
  54.         action = Intent.ACTION_MEDIA_SHARED;  
  55.         if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent");  
  56.     } else if (newState == VolumeState.SharedMnt) {  
  57.         Slog.e(TAG, "Live shared mounts not supported yet!");  
  58.         return;  
  59.     } else {  
  60.         Slog.e(TAG, "Unhandled VolumeState {" + newState + "}");  
  61.     }  
  62.   
  63.     if (action != null) {  
  64.         sendStorageIntent(action, volume, UserHandle.ALL);//发送广播给应用,但是我们没有使用广播。而是注册的回调  
  65.     }  
  66. }  

我们再来看看updatePublicVolumeState函数:

[java]  view plain  copy
  1.     private void updatePublicVolumeState(StorageVolume volume, String state) {  
  2.         final String path = volume.getPath();  
  3.         final String oldState;  
  4.         synchronized (mVolumesLock) {  
  5.             oldState = mVolumeStates.put(path, state);  
  6.             volume.setState(state);  
  7.         }  
  8.   
  9.         if (state.equals(oldState)) {  
  10.             Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s",  
  11.                     state, state, path));  
  12.             return;  
  13.         }  
  14.   
  15. ...........  
  16.   
  17.         synchronized (mListeners) {  
  18.             for (int i = mListeners.size() -1; i >= 0; i--) {//遍历回调函数  
  19.                 MountServiceBinderListener bl = mListeners.get(i);  
  20.                 try {  
  21.                     bl.mListener.onStorageStateChanged(path, oldState, state);  
  22.                 } catch (RemoteException rex) {  
  23.                     Slog.e(TAG, "Listener dead");  
  24.                     mListeners.remove(i);  
  25.                 } catch (Exception ex) {  
  26.                     Slog.e(TAG, "Listener failed", ex);  
  27.                 }  
  28.             }  
  29.         }  
  30.     }  


现在的现象是,当用户点击卸载sd卡后,updatePreferencesFromState又被调用了,而且经过验证是setting自己调用的,而非MountService中的回调。

[java]  view plain  copy
  1. private void updatePreferencesFromState() {  
  2.         // Only update for physical volumes  
  3.         if (mVolume == nullreturn;  
  4.   
  5.         mMountTogglePreference.setEnabled(true);  
  6.   
  7.         final String state = mStorageManager.getVolumeState(mVolume.getPath());  
  8.   
  9.         if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {  
  10.             mItemAvailable.setTitle(R.string.memory_available_read_only);  
  11.         } else {  
  12.             mItemAvailable.setTitle(R.string.memory_available);  
  13.         }  
  14.   
  15.         if (Environment.MEDIA_MOUNTED.equals(state)  
  16.                 || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {  
  17.                 mMountTogglePreference.setEnabled(true);//去查询sd卡的状态还是mounted,所以又置亮了。所以出现了卸载过程中,还能卸载的情况  
  18.                 mMountTogglePreference.setTitle(mResources.getString(R.string.sd_eject));  
  19.                 mMountTogglePreference.setSummary(mResources.getString(R.string.sd_eject_summary));  
  20.                   
  21.                 addPreference(mUsageBarPreference);  
  22.                 addPreference(mItemTotal);  
  23.                 addPreference(mItemAvailable);  
  24.         } else {  
  25.             if (Environment.MEDIA_UNMOUNTED.equals(state) || Environment.MEDIA_NOFS.equals(state)  
  26.                     || Environment.MEDIA_UNMOUNTABLE.equals(state)) {  
  27.                 mMountTogglePreference.setEnabled(true);  
  28.                 mMountTogglePreference.setTitle(mResources.getString(R.string.sd_mount));  
  29.                 mMountTogglePreference.setSummary(mResources.getString(R.string.sd_mount_summary));  
  30.             } else {  
  31.                 mMountTogglePreference.setEnabled(false);  
  32.                 mMountTogglePreference.setTitle(mResources.getString(R.string.sd_mount));  
  33.                 mMountTogglePreference.setSummary(mResources.getString(R.string.sd_insert_summary));  
  34.             }  
  35.   
  36.             removePreference(mUsageBarPreference);  
  37.             removePreference(mItemTotal);  
  38.             removePreference(mItemAvailable);  
  39.         }  
  40.   
  41.         if (mUsbConnected && (UsbManager.USB_FUNCTION_MTP.equals(mUsbFunction) ||  
  42.                 UsbManager.USB_FUNCTION_PTP.equals(mUsbFunction))) {  
  43.             //mMountTogglePreference.setEnabled(false);  
  44.             if (Environment.MEDIA_MOUNTED.equals(state)  
  45.                     || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {  
  46.                 mMountTogglePreference.setSummary(  
  47.                         mResources.getString(R.string.mtp_ptp_mode_summary));  
  48.             }  
  49.   
  50.             if (mFormatPreference != null) {  
  51.                 mFormatPreference.setEnabled(false);  
  52.                 mFormatPreference.setSummary(mResources.getString(R.string.mtp_ptp_mode_summary));  
  53.             }  
  54.         } else if (mFormatPreference != null) {  
  55.             mFormatPreference.setEnabled(mMountTogglePreference.isEnabled());//卸载完后,格式化应该置灰。这边卸载完,变成"安装SD卡"的titiel并且也是亮的,所以格式化也是亮的  
  56.             mFormatPreference.setSummary(mResources.getString(R.string.sd_format_summary));  
  57.         }  
  58.     }  


至于这样的两种情况,在MountService的notifyVolumeStateChange函数中增加一个Unmounting状态,在Environment.java中增加Environment.MEDIA_UNMOUNTING

[java]  view plain  copy
  1. else if (newState == VolumeState.Unmounting) {  
  2.     action = Intent.ACTION_MEDIA_EJECT;  
  3.    Log.d(TAG,"Unmounting");  
  4.    updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTING);  
  5. }  

然后在Setting增加如下,在最前面增加一个Memory.STATE_UNMOUNTING状态,如果是这个状态,将sd卡状态和格式化这两项都置灰。

[java]  view plain  copy
  1. private void updatePreferencesFromState() {  
  2.     if (mVolume == null) {  
  3.         return;  
  4.     }  
  5.   
  6.     mMountTogglePreference.setEnabled(true);  
  7.   
  8.     final String state = mStorageManager.getVolumeState(mVolume.getPath());  
  9.     if (mVolume == null || (state != null && state.equals(Memory.STATE_UNMOUNTING))) {  
  10.         Log.i(TAG, "state return");  
  11.         mMountTogglePreference.setEnabled(false);  
  12.         mFormatPreference.setEnabled(false);  
  13.         mMountTogglePreference.setTitle(mResources.getString(R.string.sd_ejecting_title));  
  14.         mMountTogglePreference.setSummary(mResources.getString(R.string.sd_ejecting_summary));  
  15.        return;  
  16.     }  

这样这个问题就解决了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值