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

来源:互联网 发布:python mac 编辑:程序博客网 时间:2024/04/27 21:33

最终效果


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 := optionalLOCAL_SRC_FILES := $(call all-java-files-under, src)LOCAL_PACKAGE_NAME := HelloWordLOCAL_CERTIFICATE := platforminclude $(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为其添加如下代码:
@Overridepublic AppVoiceEntryInfo getAppVoiceEntryInfo(String packageName,String xmlName, String bnfName) throws NameNotFoundException {// TODO Auto-generated method stub throw new UnsupportedOperationException();}
找到PackageManager的实现类之二:MockPackageManager为其添加如下代码:
@Overridepublic 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)这个构造方式是在哪被调用的即初始化的

@Overridepublic 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<PermissionInfo> queryPermissionsByGroup(String group, int flags);        PermissionGroupInfo getPermissionGroupInfo(String name, int flags);        List<PermissionGroupInfo> 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<ResolveInfo> queryIntentActivities(in Intent intent,             String resolvedType, int flags);    List<ResolveInfo> queryIntentActivityOptions(            in ComponentName caller, in Intent[] specifics,            in String[] specificTypes, in Intent intent,            String resolvedType, int flags);    List<ResolveInfo> queryIntentReceivers(in Intent intent,            String resolvedType, int flags);    ResolveInfo resolveService(in Intent intent,            String resolvedType, int flags);    List<ResolveInfo> queryIntentServices(in Intent intent,            String resolvedType, int flags);    List<PackageInfo> getInstalledPackages(int flags);    List<ApplicationInfo> getInstalledApplications(int flags);    /**     * Retrieve all applications that are marked as persistent.     *      * @return A List<applicationInfo> containing one entry for each persistent     *         application.     */    List<ApplicationInfo> 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<String> outNames,            inout List<ProviderInfo> outInfo);    List<ProviderInfo> queryContentProviders(            String processName, int uid, int flags);    InstrumentationInfo getInstrumentationInfo(            in ComponentName className, int flags);    List<InstrumentationInfo> 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<PackageInfo> 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<IntentFilter> outFilters,            out List<ComponentName> 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<String, String> map = new HashMap<String, String>();public int describeContents() {// TODO Auto-generated method stubreturn 0;}public void writeToParcel(Parcel dest, int flags) {// TODO Auto-generated method stubdest.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<AppVoiceEntryInfo> CREATOR = new Parcelable.Creator<AppVoiceEntryInfo>() {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-lastChecking 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









原创粉丝点击