1. 程式人生 > >Android設定裡面預設儲存器選項(default write disk)的實現

Android設定裡面預設儲存器選項(default write disk)的實現

    原生的Android設定裡面沒有預設儲存器的選項,但是MTK偏偏加上了這個功能,可能MTK覺得這個比較有用吧,所以,他們在原生的基礎上面做了修改,加上了這個功能。但是高通平臺沒有這個功能,相對MTK來說,高通比較嚴謹一點,不會隨隨便便加上一些功能,但是MTK平臺優化了很多東西(有有點也有缺點),開發者這可能是很多山寨手機選擇MTK平臺的原因吧。

     我給“預設儲存器”做了一個簡單的定義:一些內建應用的資料存放位置。當然,如果其他應用知道這個介面(不是標準介面,所以只有開發者本人知道,或者MTK的人),也可以使用該功能。

    之前接到一個在高通平臺上的手機裡面加上預設儲存器的選項,即如果選擇本地記憶體,一些內建應用的資料將儲存到本地記憶體裡面,如果選擇SD卡儲存,則這些應用的資料將會儲存到SD卡里面。借鑑MTK平臺的實現方法,整理其思路是:通過SystemProperties介面往系統記憶體裡面寫入儲存路徑(set),然後在一些指定應用裡面儲存資料的時候判斷當前預設儲存器,使用get方法讀取這個屬性。為什麼使用SystemProperties,因為其設定的值全域性都可以使用,即不同應用都可以通過共享記憶體取出其值,解決了程序間通訊的問題。

    1:我們先在framework層加上一些自定義的介面檔案。我加的位置是 ....../frameworks/base/core/java/android/os/storage/,新增的檔名StorageManagerEx.java,內容如下:

package android.os.storage;	
import android.util.Log;	
import com.android.internal.R;	
import android.os.SystemProperties;	
import java.io.File;	
import android.os.Environment;	


public class StorageManagerEx {	
»       private static final String TAG ="StorageManagerEx";	
»       private static final String PROP_SD_DEFAULT_PATH = "persist.sys.sd.defaultpath";	
»       	
»       private static final String STORAGE_PATH_SD1 ="/storage/sdcard0";	
»       private static final String STORAGE_PATH_SD2 ="/storage/sdcard1";	
»       private static final String STORAGE_PATH_SD1_ICS = "/mnt/sdcard";	
»       private static final String STORAGE_PATH_SD2_ICS = "/mnt/sdcard2";	
»       	
»       private static final String STORAGE_PATH_SHARE_SD = "/storage/emulated/0";	
»       	
»       /**	
»        * Return default path for writing.	
»        * @return default path.	
»        * @hide	
»        * @internal	
»        */	
   public static String getDefaultPath(){
»          String path = STORAGE_PATH_SD1;	
»          try {	
»       »          path = SystemProperties.get(PROP_SD_DEFAULT_PATH);	
»       »          Log.i(TAG,"default path = "+path);	
»          } catch (IllegalArgumentException e) {	
»       »          Log.e(TAG,"IllegalArgumentException when get default path:"+e);	
»          }	
»          //Property will be empty when first boot should set to default 	
»          if(path.equals("")){	
»       »          Log.i(TAG,"getDefaultPath empty! set to default");	
»       »          //Here may be some problems.refer to MTK:only share sd and no swap,internal path 
is 	
»       »          //"/storage/emulated/0",i don't know "share" and "no swap",so i skip. 	
»       »          //           if (FeatureOption.MTK_SHARED_SDCARD && !FeatureOption.MTK_2SDCARD_SW
AP) {»       »       
»       »          //               setDefaultPath(STORAGE_PATH_SHARE_SD); 	
»       »          //               path = STORAGE_PATH_SHARE_SD; 	
»       »          //           } else { 	
»       »          //               setDefaultPath(STORAGE_PATH_SD1); 	
»       »          //               path = STORAGE_PATH_SD1; 	
»       »          //           } 	
»       »          setDefaultPath(STORAGE_PATH_SD1);	
»       »          path = STORAGE_PATH_SD1;	
»          }	
»          	
»          //Here we don't care multi user which will be used by google,ignore and go on. 	
»          	
»          //MOTA upgrade from ICS to JB,update defaultPath to JB. 	
»          if(path.equals(STORAGE_PATH_SD1_ICS)){	
»       »          path = STORAGE_PATH_SD1;	
»       »          setDefaultPath(path);	
»          }else if(path.equals(STORAGE_PATH_SD2_ICS)){	
»       »          path = STORAGE_PATH_SD2;	
»       »          setDefaultPath(path);	
»          }	
»          	
»          Log.i(TAG,"getDefaultPath path="+path);	
»          return path;	
   }	
   	
   /**	
    * set default path for Appto storage data	
    * this only can used by settings.	
    * 	
    * @param path	
    * @hide	
    * @internal	
    */	
   public static void setDefaultPath(String path){	
»          Log.i(TAG,"setDefaultPath path = " + path);	
»          if (path == null) {	
»       »          Log.e(TAG,"setDefaultPath error! path = null");	
»       »          return;	
»          }	
»          	
»          try {	
»       »          SystemProperties.set(PROP_SD_DEFAULT_PATH,path);	
»          } catch (IllegalArgumentException e) {	
»       »          Log.e(TAG,"IllegalArgumentException when setDefaultPath:" + e);	
»          }	
   }	
   	
   /**	
    * Returns external SD card path.»       /sdcard2	
    * @hide	
    * @internal	
    */	
//   public static String getExternalStoragePath(){»       //method 1: 	
//»          String sdCardDir = null; 	
//       android.os.storage.StorageManager storageManager = 	
//               (android.os.storage.StorageManager) context 	
//                       .getSystemService(Context.STORAGE_SERVICE); 	
//       StorageVolume[] volumes = storageManager.getVolumeList(); 	
//       for (int i = 0; i < volumes.length; i++) { 	
//           if (volumes[i].isRemovable() && volumes[i].allowMassStorage()) { 	
//               sdCardDir = volumes[i].getPath(); 	
//               break; 	
//           } 	
//       } 	
//       return sdCardDir; 	
//   } 
   	
 public static String getExternalStoragePath(){»       //method 2: 	
   String sdCardDir = null;	
   String state = Environment.getStorageState(new File(STORAGE_PATH_SD2));	
   	
   if(state.equals(Environment.MEDIA_MOUNTED)){	
»          sdCardDir = STORAGE_PATH_SD2;	
   }else if(state.equals(Environment.MEDIA_UNMOUNTED)){	
»          sdCardDir = Environment.MEDIA_UNMOUNTED;	
   }else{	
»          sdCardDir = STORAGE_PATH_SD2;	
   }	
   return sdCardDir;  	
}	
   	
   	
   /**	
    * Returns internal storage path.	
    * @return	
    * @hide	
    * @internal	
    */	
   public static String getInternalStoragePath(){	
»          String sdCardDir = null;	
»          String state = Environment.getStorageState(new File(STORAGE_PATH_SHARE_SD));	
»          	
»          if(state.equals(Environment.MEDIA_MOUNTED)){	
»       »          sdCardDir = STORAGE_PATH_SD1;	
»          }else if(state.equals(Environment.MEDIA_UNMOUNTED)){	
»       »          sdCardDir = Environment.MEDIA_UNMOUNTED;	
»          }else{	
»       »          sdCardDir = STORAGE_PATH_SD1;	
»          }	
»          return sdCardDir;  	
   }	1
   	
} 

    定義的主要作用是往系統記憶體的屬性裡面新增屬性presist.sys.sd.default.我們可以進入adb裡面檢視和修改一些屬性1:adb shell 2:getprop + 鍵(或不加) tip:我們也可以setprop + 鍵 +值


     2:在設定裡面新增預設儲存器的選項:


在Settings的工程裡面的.....res/xml/device_info_memory.xml的檔案裡面新增

......<span style="white-space:pre">	</span><PreferenceCategory 	
        android:key="memory_select"	
        android:title="@string/select_memory" />     ......
然後在PreferenceCategory裡面新增RadioButtonPreference  (此處省略)

在Memroy.java檔案裡面新增

private void initDefaultWriteDisk(){	
    »       mDefaultWriteCategory = (PreferenceCategory)findPreference(DEFAULT_WRITE_CATEGORY_KEY);	
        List<RadioButtonPreference> defaultWritePreference = new ArrayList<RadioButtonPreference>();	
        StorageVolume[] volumes = mStorageManager.getVolumeList();	
        List<StorageVolume> storageVolumesEx = initVolumeList(volumes);	
        for (int i = 0; i < storageVolumesEx.size(); i++) {	
        »       StorageVolume volumn = storageVolumesEx.get(i);	
        »       RadioButtonPreference avalibileDisk = new RadioButtonPreference(getActivity());	
        »       String path = volumn.getPath();»       //volumn path 	
        »       android.util.Log.i("haiyong.liu","volumn.path="+path);	
        »       String state = Environment.getStorageState(new File(path));	
        »       	
        »       avalibileDisk.setKey(path);	
        »       avalibileDisk.setTitle(volumn.getDescription(getActivity()));	
        »       avalibileDisk.setPath(path);	
        »       avalibileDisk.setOnPreferenceChangeListener(this);	
        »       defaultWritePreference.add(avalibileDisk);	
        »       android.util.Log.e("haiyong.liu","Environment="+state);	
        »       if(state.equals(Environment.MEDIA_UNMOUNTED)||state.equals(Environment.MEDIA_REMOVED
)){	
        »       »       	
        »       }else {	
        »       »       mDefaultWriteCategory.addPreference(avalibileDisk);	
        »       »       if(path.equals(StorageManagerEx.getDefaultPath())){	
        »       »       »       avalibileDisk.setChecked(true);	
        »       »       »       mDeafultWritePathPref = avalibileDisk;	
        »       »       }else{	
        »       »       »       avalibileDisk.setChecked(false);	
        »       »       }	
        »       }	
»       »       }	
    }	
    	
    private List<StorageVolume> initVolumeList(StorageVolume[] volumes){	
    »       List<StorageVolume> storageVolumes = new ArrayList<StorageVolume>();	
    »       /*if(UserManager.supportsMultipleUsers()){»       //return the current user's volumn lis
t if supported,otherwise ignore.	
    »       »       StorageVolume[] sv = mStorageManager.getVolumeListAsUser();	
    »       »       for (int i = 0; i < sv.length; i++) {	
                if (!"not_present".equals(mStorageManager.getVolumeState(volumes[i].getPath()))) {	
                    storageVolumes.add(volumes[i]);	
                }	
            }	
    »       »       return storageVolumes;	
    »       }*/	
    »       	
        for (int i = 0; i < volumes.length; i++) {	
            if (!"not_present".equals(mStorageManager.getVolumeState(volumes[i].getPath()))) {	
                storageVolumes.add(volumes[i]);	
            }	
        }	
        	
        return storageVolumes;	
    }	
    	
    @Override	
    public boolean onPreferenceChange(Preference preference, Object newValue) {	

        if (preference != null && preference instanceof RadioButtonPreference) {	
            if (mDeafultWritePathPref != null) {	
                mDeafultWritePathPref.setChecked(false);	
            }	
            StorageManagerEx.setDefaultPath(preference.getKey());	
            mDeafultWritePathPref = (RadioButtonPreference) preference;	
            return true;	
        }	
        return false;	
    }

然後在oncreate方法裡面呼叫
initDefaultWriteDisk()
這個方法,這個方法放在Memory.java的onCreate(...)方法裡面,另外,StorageManagerEx.setDefaultPath(),這個方法只可以在settings這個apk裡面使用,即只有settings這個apk可以寫入。

    3:找到對應需要新增該功能的工程,我們需要新增的是Camrea2,藍芽,下載器,錄音這幾個Apk,找到這幾個原始碼儲存資料的地方,將儲存位置改為StorageManagerEx.getDefaultPath()

tip:SystemProperties寫入資料時候需要許可權。在Manifests.xml檔案加上android:sharedUserId="android.uid.system",在Android.mk中,將LOCAL_CERTIFICATE := XXX修改成LOCAL_CERTIFICATE :=platform。