android 一个应用去获取另一个应用assets下面的资源通过框架代码桥梁------项目实战成功案例

最终效果


HelloWord工程应用代码:

package com.pateo;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import com.pateo.R;
import android.content.pm.PackageManager;

public class HelloWordActivity extends Activity {
	
	TextView tv ;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        tv = (TextView)findViewById(R.id.tv);
        
        PackageManager pm = getPackageManager();
        try{
        	tv.setText("result : " + pm.getAppVoiceEntryInfo("packageName", "xmlName", "bnfName").speechContent);
        }catch( android.content.pm.PackageManager.NameNotFoundException e){
        	tv.setText("" + e);
        }
       
    }
}
上面getAppVoiceEntryInfo不是PackageManager自带的方法是我自己添加的方法

我是自己写了个HelloWord工程,放入到源码中,自己的应用怎么放入框架中要遵循:修改/bulid/target/product/generic.mk 把工程编译到系统中

generic.mk

#
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# This is a generic product that isn't specialized for a specific device.
# It includes the base Android platform.

PRODUCT_PACKAGES := \
    AccountAndSyncSettings \
    CarHome \
    DeskClock \
    AlarmProvider \
    Bluetooth \
    Calculator \
    Calendar \
    Camera \
    CertInstaller \
    DrmProvider \
    Email \
    Gallery3D \
    LatinIME \
    Launcher2 \
    Mms \
    Music \
    Provision \
    Protips \
    QuickSearchBox \
    Settings \
    Sync \
    Updater \
    CalendarProvider \
    SyncProvider \
    Helloworld

HelloWord的Android.mk文件

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_PACKAGE_NAME := HelloWord
LOCAL_CERTIFICATE := platform

include $(BUILD_PACKAGE)

# Use the folloing include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))

把HelloWord工程放入package/apps/目录下面,在此工程的assets木下建立一个xml文件里面写一些内容,我在这里建的文件名:voice_recognition.xml

到这里基本应用的代码完成了

下面是框架中的一些实现步骤

Ctrl+Shift+T [Eclipse的快捷键方式,下同]搜索类:PackageManager为其添加如下代码:

    /**
     * 语音识别获取应用的识别词条的动作的启动信息
     * @param packageName 应用的包名
     * @param xmlName 词条对应的动作定义的文件
     * @param bnfName 词条识别的入科大库的文件
     * @return
     * @throws NameNotFoundException
     */
    public abstract AppVoiceEntryInfo getAppVoiceEntryInfo(String packageName,
    		String xmlName,String bnfName)throws NameNotFoundException;
PackageManager是个抽象类,我们F4找到它的实现类之一:MockPackageManager为其添加如下代码:
	@Override
	public AppVoiceEntryInfo getAppVoiceEntryInfo(String packageName,
			String xmlName, String bnfName) throws NameNotFoundException {
		// TODO Auto-generated method stub
		 throw new UnsupportedOperationException();
	}
找到PackageManager的实现类之二:MockPackageManager为其添加如下代码:
		@Override
		public AppVoiceEntryInfo getAppVoiceEntryInfo(String packageName,
				String xmlName, String bnfName) throws NameNotFoundException {
			try {
				AppVoiceEntryInfo appVoiceEntryInfo = mPM.getAppVoiceEntryInfo(
						"packageName", "xmlName", "bnfName");
				Log.d(TAG,
						"============================getAppVoiceEntryInfo====================================");
				return appVoiceEntryInfo;
			} catch (RemoteException e) {
				throw new RuntimeException("Package manager has died", e);
			}
		}
上面的mPM的定义:

		private final IPackageManager mPM;

它是怎么被赋值的呢Ctril+F找“mPM = ”,找到如下赋值的地方:

		ApplicationPackageManager(ContextImpl context, IPackageManager pm) {
			mContext = context;
			mPM = pm;
		}

通过Ctril+Shift+G找到ApplicationPackageManager(ContextImpl context, IPackageManager pm)这个构造方式是在哪被调用的即初始化的

	@Override
	public PackageManager getPackageManager() {
		if (mPackageManager != null) {
			return mPackageManager;
		}

		IPackageManager pm = ActivityThread.getPackageManager();
		if (pm != null) {
			// Doesn't matter if we make more than one instance.
			return (mPackageManager = new ApplicationPackageManager(this, pm));
		}

		return null;
	}

接着找pm是怎么来的,点击getPackageManager()这个方法,进入ActivityThread有关这个方法的实现,代码如下:

    public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
            return sPackageManager;
        }
        IBinder b = ServiceManager.getService("package");
        //Slog.v("PackageManager", "default service binder = " + b);
        sPackageManager = IPackageManager.Stub.asInterface(b);
        //Slog.v("PackageManager", "default service = " + sPackageManager);
        return sPackageManager;
    }

从上面我们可以知道了,我们需要找到IPackageManager.aidl文件,通过Ctril+H找到这个aidl文件,当然你也可以在Ubuntu下通过grep过滤来找到这个aidl文件,个人习惯不同


这个aidl文件中加一个    AppVoiceEntryInfo getAppVoiceEntryInfo(String packageName, String xmlName, String bnfName);接口方法

/*
**
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

package android.content.pm;

import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.content.IntentSender;

import android.content.pm.AppVoiceEntryInfo;

/**
 *  See {@link PackageManager} for documentation on most of the APIs
 *  here.
 * 
 *  {@hide}
 */
interface IPackageManager {

    AppVoiceEntryInfo getAppVoiceEntryInfo(String packageName, String xmlName, String bnfName);

    PackageInfo getPackageInfo(String packageName, int flags);
    int getPackageUid(String packageName);
    int[] getPackageGids(String packageName);
    
    String[] currentToCanonicalPackageNames(in String[] names);
    String[] canonicalToCurrentPackageNames(in String[] names);

    PermissionInfo getPermissionInfo(String name, int flags);
    
    List queryPermissionsByGroup(String group, int flags);
    
    PermissionGroupInfo getPermissionGroupInfo(String name, int flags);
    
    List getAllPermissionGroups(int flags);
    
    ApplicationInfo getApplicationInfo(String packageName, int flags);

    ActivityInfo getActivityInfo(in ComponentName className, int flags);

    ActivityInfo getReceiverInfo(in ComponentName className, int flags);

    ServiceInfo getServiceInfo(in ComponentName className, int flags);

    int checkPermission(String permName, String pkgName);
    
    int checkUidPermission(String permName, int uid);
    
    boolean addPermission(in PermissionInfo info);
    
    void removePermission(String name);
    
    boolean isProtectedBroadcast(String actionName);
    
    int checkSignatures(String pkg1, String pkg2);
    
    int checkUidSignatures(int uid1, int uid2);
    
    String[] getPackagesForUid(int uid);
    
    String getNameForUid(int uid);
    
    int getUidForSharedUser(String sharedUserName);
    
    ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags);

    List queryIntentActivities(in Intent intent, 
            String resolvedType, int flags);

    List queryIntentActivityOptions(
            in ComponentName caller, in Intent[] specifics,
            in String[] specificTypes, in Intent intent,
            String resolvedType, int flags);

    List queryIntentReceivers(in Intent intent,
            String resolvedType, int flags);

    ResolveInfo resolveService(in Intent intent,
            String resolvedType, int flags);

    List queryIntentServices(in Intent intent,
            String resolvedType, int flags);

    List getInstalledPackages(int flags);

    List getInstalledApplications(int flags);

    /**
     * Retrieve all applications that are marked as persistent.
     * 
     * @return A List containing one entry for each persistent
     *         application.
     */
    List getPersistentApplications(int flags);

    ProviderInfo resolveContentProvider(String name, int flags);

    /**
     * Retrieve sync information for all content providers.
     * 
     * @param outNames Filled in with a list of the root names of the content
     *                 providers that can sync.
     * @param outInfo Filled in with a list of the ProviderInfo for each
     *                name in 'outNames'.
     */
    void querySyncProviders(inout List outNames,
            inout List outInfo);

    List queryContentProviders(
            String processName, int uid, int flags);

    InstrumentationInfo getInstrumentationInfo(
            in ComponentName className, int flags);

    List queryInstrumentation(
            String targetPackage, int flags);

    /**
     * Install a package.
     *
     * @param packageURI The location of the package file to install.
     * @param observer a callback to use to notify when the package installation in finished.
     * @param flags - possible values: {@link #FORWARD_LOCK_PACKAGE},
     * {@link #REPLACE_EXISITING_PACKAGE}
     * @param installerPackageName Optional package name of the application that is performing the
     * installation. This identifies which market the package came from.
     */
    void installPackage(in Uri packageURI, IPackageInstallObserver observer, int flags,
            in String installerPackageName);

    void finishPackageInstall(int token);

    /**
     * Delete a package.
     *
     * @param packageName The fully qualified name of the package to delete.
     * @param observer a callback to use to notify when the package deletion in finished.
     * @param flags - possible values: {@link #DONT_DELETE_DATA}
     */
    void deletePackage(in String packageName, IPackageDeleteObserver observer, int flags);

    String getInstallerPackageName(in String packageName);

    void addPackageToPreferred(String packageName);
    
    void removePackageFromPreferred(String packageName);
    
    List getPreferredPackages(int flags);

    void addPreferredActivity(in IntentFilter filter, int match,
            in ComponentName[] set, in ComponentName activity);

    void replacePreferredActivity(in IntentFilter filter, int match,
            in ComponentName[] set, in ComponentName activity);

    void clearPackagePreferredActivities(String packageName);

    int getPreferredActivities(out List outFilters,
            out List outActivities, String packageName);
    
    /**
     * As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}.
     */
    void setComponentEnabledSetting(in ComponentName componentName,
            in int newState, in int flags);

    /**
     * As per {@link android.content.pm.PackageManager#getComponentEnabledSetting}.
     */
    int getComponentEnabledSetting(in ComponentName componentName);
    
    /**
     * As per {@link android.content.pm.PackageManager#setApplicationEnabledSetting}.
     */
    void setApplicationEnabledSetting(in String packageName, in int newState, int flags);
    
    /**
     * As per {@link android.content.pm.PackageManager#getApplicationEnabledSetting}.
     */
    int getApplicationEnabledSetting(in String packageName);
    
    /**
     * Free storage by deleting LRU sorted list of cache files across
     * all applications. If the currently available free storage
     * on the device is greater than or equal to the requested
     * free storage, no cache files are cleared. If the currently
     * available storage on the device is less than the requested
     * free storage, some or all of the cache files across
     * all applications are deleted (based on last accessed time)
     * to increase the free storage space on the device to
     * the requested value. There is no guarantee that clearing all
     * the cache files from all applications will clear up
     * enough storage to achieve the desired value.
     * @param freeStorageSize The number of bytes of storage to be
     * freed by the system. Say if freeStorageSize is XX,
     * and the current free storage is YY,
     * if XX is less than YY, just return. if not free XX-YY number
     * of bytes if possible.
     * @param observer call back used to notify when
     * the operation is completed
     */
     void freeStorageAndNotify(in long freeStorageSize,
             IPackageDataObserver observer);

    /**
     * Free storage by deleting LRU sorted list of cache files across
     * all applications. If the currently available free storage
     * on the device is greater than or equal to the requested
     * free storage, no cache files are cleared. If the currently
     * available storage on the device is less than the requested
     * free storage, some or all of the cache files across
     * all applications are deleted (based on last accessed time)
     * to increase the free storage space on the device to
     * the requested value. There is no guarantee that clearing all
     * the cache files from all applications will clear up
     * enough storage to achieve the desired value.
     * @param freeStorageSize The number of bytes of storage to be
     * freed by the system. Say if freeStorageSize is XX,
     * and the current free storage is YY,
     * if XX is less than YY, just return. if not free XX-YY number
     * of bytes if possible.
     * @param pi IntentSender call back used to
     * notify when the operation is completed.May be null
     * to indicate that no call back is desired.
     */
     void freeStorage(in long freeStorageSize,
             in IntentSender pi);
     
    /**
     * Delete all the cache files in an applications cache directory
     * @param packageName The package name of the application whose cache
     * files need to be deleted
     * @param observer a callback used to notify when the deletion is finished.
     */
    void deleteApplicationCacheFiles(in String packageName, IPackageDataObserver observer);
    
    /**
     * Clear the user data directory of an application.
     * @param packageName The package name of the application whose cache
     * files need to be deleted
     * @param observer a callback used to notify when the operation is completed.
     */
    void clearApplicationUserData(in String packageName, IPackageDataObserver observer);
    
   /**
     * Get package statistics including the code, data and cache size for
     * an already installed package
     * @param packageName The package name of the application
     * @param observer a callback to use to notify when the asynchronous
     * retrieval of information is complete.
     */
    void getPackageSizeInfo(in String packageName, IPackageStatsObserver observer);
    
    /**
     * Get a list of shared libraries that are available on the
     * system.
     */
    String[] getSystemSharedLibraryNames();

    /**
     * Get a list of features that are available on the
     * system.
     */
    FeatureInfo[] getSystemAvailableFeatures();

    boolean hasSystemFeature(String name);
    
    void enterSafeMode();
    boolean isSafeMode();
    void systemReady();
    boolean hasSystemUidErrors();
    
    /**
     * Ask the package manager to perform dex-opt (if needed) on the given
     * package, if it already hasn't done mode.  Only does this if running
     * in the special development "no pre-dexopt" mode.
     */
    boolean performDexOpt(String packageName);

    /**
     * Update status of external media on the package manager to scan and
     * install packages installed on the external media. Like say the
     * MountService uses this to call into the package manager to update
     * status of sdcard.
     */
    void updateExternalMediaStatus(boolean mounted, boolean reportStatus);

    String nextPackageToClean(String lastPackage);

    void movePackage(String packageName, IPackageMoveObserver observer, int flags);
    
    boolean addPermissionAsync(in PermissionInfo info);

    boolean setInstallLocation(int loc);
    int getInstallLocation();
}

由哪个类来实现上面这个框架方法呢?我通过找关键字IPackageManager.Stub找到了class PackageManagerService extends IPackageManager.Stub,下面我们就需要来实现这个抽象方法了:

    public AppVoiceEntryInfo getAppVoiceEntryInfo(String packageName, String xmlName,String bnfName){
    	AppVoiceEntryInfo appVoiceEntryInfo = new AppVoiceEntryInfo();
    	appVoiceEntryInfo.speechContent = voiceContent;
    	 Log.d(TAG,"getAppVoiceEntryInfo method appVoiceEntryInfo.speechContent : " +  appVoiceEntryInfo.speechContent);
    	return appVoiceEntryInfo;
    }

先看实体类
package android.content.pm;

import java.util.HashMap;

import android.os.Parcel;
import android.os.Parcelable;

public class AppVoiceEntryInfo implements Parcelable {

	public String packageName;

	public String activityName;
	
	public String serviceName;

	public String xmlName;
	
	public String bnfName;

	public String entry;

	public String uri;

	public String recognitionType;

	public String speechContent;

	public String action;

	public HashMap map = new HashMap();

	public int describeContents() {
		// TODO Auto-generated method stub
		return 0;
	}

	public void writeToParcel(Parcel dest, int flags) {
		// TODO Auto-generated method stub
		dest.writeMap(map);
		dest.writeString(packageName);
		dest.writeString(activityName);
		dest.writeString(xmlName);
		dest.writeString(bnfName);
		dest.writeString(entry);
		dest.writeString(uri);
		dest.writeString(recognitionType);
		dest.writeString(speechContent);
		dest.writeString(action);
	}

	public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
		public AppVoiceEntryInfo createFromParcel(Parcel source) {
			return new AppVoiceEntryInfo(source);
		}

		public AppVoiceEntryInfo[] newArray(int size) {
			return new AppVoiceEntryInfo[size];
		}
	};

	private AppVoiceEntryInfo(Parcel source){
		packageName = source.readString();
		activityName = source.readString();
		xmlName = source.readString();
		bnfName = source.readString();
		entry = source.readString();
		uri = source.readString();
		recognitionType = source.readString();
		speechContent = source.readString();
		action = source.readString();
		map = source.readHashMap(HashMap.class.getClassLoader());  
				
	}

	public AppVoiceEntryInfo() {
		// TODO Auto-generated constructor stub
	}
}


上面的voiceContent变量是我定义的

    public static String voiceContent = null;

这个变量的赋值:

    private PackageParser.Package scanPackageLI(File scanFile,
            int parseFlags, int scanMode) {
        mLastScanError = PackageManager.INSTALL_SUCCEEDED;
        String scanPath = scanFile.getPath();
        parseFlags |= mDefParseFlags;
        PackageParser pp = new PackageParser(scanPath);
        pp.setSeparateProcesses(mSeparateProcesses);
        final PackageParser.Package pkg = pp.parsePackage(scanFile,
                scanPath, mMetrics, parseFlags);
        
        voiceContent = pp.voiceContent;
        Log.d(TAG,"Voice Contect : " +  voiceContent);

上面pp.voiceContent;的值是怎么来的呢?接着看PackageParser中的实现:

    public static String voiceContent = null;
    
    public String convertStreamToString(InputStream is) {      
        /*  
          * To convert the InputStream to String we use the BufferedReader.readLine()  
          * method. We iterate until the BufferedReader return null which means  
          * there's no more data to read. Each line will appended to a StringBuilder  
          * and returned as String.  
          */     
         BufferedReader reader = new BufferedReader(new InputStreamReader(is));      
         StringBuilder sb = new StringBuilder();      
     
         String line = null;      
        try {      
            while ((line = reader.readLine()) != null) {      
                 sb.append(line + "\n");      
             }      
         } catch (IOException e) {      
             e.printStackTrace();      
         } finally {      
            try {      
                 is.close();      
             } catch (IOException e) {      
                 e.printStackTrace();      
             }      
         }      
     
        return sb.toString();      
     }      

    public Package parsePackage(File sourceFile, String destCodePath,
            DisplayMetrics metrics, int flags) {
        mParseError = PackageManager.INSTALL_SUCCEEDED;

        mArchiveSourcePath = sourceFile.getPath();
       
        
        if (!sourceFile.isFile()) {
            Log.w(TAG, "Skipping dir: " + mArchiveSourcePath);
            mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
            return null;
        }
        if (!isPackageFilename(sourceFile.getName())
                && (flags&PARSE_MUST_BE_APK) != 0) {
            if ((flags&PARSE_IS_SYSTEM) == 0) {
                // We expect to have non-.apk files in the system dir,
                // so don't warn about them.
                Log.w(TAG, "Skipping non-package file: " + mArchiveSourcePath);
            }
            mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
            return null;
        }

        if ((flags&PARSE_CHATTY) != 0 && Config.LOGD) Log.d(
            TAG, "Scanning package: " + mArchiveSourcePath);

        XmlResourceParser parser = null;
        AssetManager assmgr = null;
        InputStream inputStream = null;
        boolean assetError = true;
        try {
            assmgr = new AssetManager();
            int cookie = assmgr.addAssetPath(mArchiveSourcePath);
            if(cookie != 0) {
            	 Log.d(TAG, "sourceFile : " + sourceFile + " destCodePath : " + destCodePath + " flags : " + flags + " cookie : " + cookie
            			 + " ArchiveSourcePath : " + mArchiveSourcePath); 
            	parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
            	try{
            		inputStream = assmgr.open("voice_recognition.xml");
            	}catch(Exception e){
            		 Log.d(TAG,"" + e);
            	}
                if(inputStream != null){
                	 Log.d(TAG,"============================= success =========================="  );
                	 voiceContent = convertStreamToString(inputStream);
                	 Log.d(TAG,"Voice Contect : " +  voiceContent);
                }

看到上面你应该都明白了吧,呵呵,我也该睡觉了明天还要上班,我电脑太慢, 在Eclipse里面每写个东西就卡死要等一会,上面是个Demo只是为了说明意思,代码不值钱,值钱的是想法,想法哪里来靠看源码啊。


有关过程中的停顿

Checking API: checkapi-last
Checking API: checkapi-current
(unknown): error 3: Added class AppVoiceEntryInfo to package android.content.pm
(unknown): error 4: Added public method android.content.pm.PackageManager.getAppVoiceEntryInfo

******************************
You have tried to change the API from what has been previously approved.

To make these errors go away, you have two choices:
   1) You can add "@hide" javadoc comments to the methods, etc. listed in the
      errors above.

   2) You can update current.xml by executing the following command:
         make update-api

      To submit the revised current.xml to the main Android repository,
      you will need approval.
******************************



make: *** [out/target/common/obj/PACKAGING/checkapi-current-timestamp] 错误 38

上面提示当你修改了框架代码你更改了api需要执行命令#make update-api









你可能感兴趣的:(Framework)