解决Android4.4 Widget之AppWidgetHost.allocateAppWidgetId()返回-1

【原创文章,转载请声明】转自http://blog.csdn.net/allen_704/article/details/28640827

Android4.4对widget有了一些变化,遇到的问题如题所示,无法创建widget。

看4.4的源码,在frameworks\base\services\java\com\android\server\AppWidgetServiceImpl.java这个类里面

public int allocateAppWidgetId(String packageName, int hostId) {
        int callingUid = enforceSystemOrCallingUid(packageName);
        synchronized (mAppWidgetIds) {
            if (!mHasFeature) {
                return -1;
            }
            ensureStateLoadedLocked();
            int appWidgetId = mNextAppWidgetId++;

            Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);

            AppWidgetId id = new AppWidgetId();
            id.appWidgetId = appWidgetId;
            id.host = host;

            host.instances.add(id);
            mAppWidgetIds.add(id);

            saveStateAsync();
            if (DBG) log("Allocating AppWidgetId for " + packageName + " host=" + hostId
                    + " id=" + appWidgetId);
            return appWidgetId;
        }
    }

看到这里,瞬间怀疑方法开始的这个if(!mHasFeature)这个判断,为了更进一步确认看一下4.1的源码,手上正好也有

 public int allocateAppWidgetId(String packageName, int hostId) {
        int callingUid = enforceCallingUid(packageName);
        synchronized (mAppWidgetIds) {
            ensureStateLoadedLocked();
            int appWidgetId = mNextAppWidgetId++;

            Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);

            AppWidgetId id = new AppWidgetId();
            id.appWidgetId = appWidgetId;
            id.host = host;

            host.instances.add(id);
            mAppWidgetIds.add(id);

            saveStateLocked();

            return appWidgetId;
        }
    }

看到了吧!基本可以判断是4.4中的那个判断引起的了,此时,来追踪mHasFeature这个变量。其声明和赋值如下

final boolean mHasFeature;
//-------------------------------------
AppWidgetServiceImpl(Context context, int userId, Handler saveStateHandler) {
        mContext = context;
        mPm = AppGlobals.getPackageManager();
        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        mUserId = userId;
        mSaveStateHandler = saveStateHandler;
        mHasFeature = context.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_APP_WIDGETS);
        computeMaximumWidgetBitmapMemory();
    }

到了这里,去查PackageManager的hasSystemFeature方法,最后实现是在这个地方frameworks\base\services\java\com\android\server\pm\PackageManagerService.java

public boolean hasSystemFeature(String name) {
        synchronized (mPackages) {
            return mAvailableFeatures.containsKey(name);
        }
    }

继续看mAvailableFeatures这个集合是在哪里声明赋值的,首先看声明

// These are the features this devices supports that were read from the
    // etc/permissions.xml file.
    final HashMap mAvailableFeatures =
            new HashMap();

高潮来了, 看注释!These are the features this devices supports that were read from the etc/permissions.xml file.哈哈,到这里基本就知道问题在哪了,不过顺便也看看mAvailableFeatures是怎么赋值的

private void readPermissionsFromXml(File permFile) {
        FileReader permReader = null;
        try {
            permReader = new FileReader(permFile);
        } catch (FileNotFoundException e) {
            Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
            return;
        }

        try {
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(permReader);

            XmlUtils.beginDocument(parser, "permissions");

            while (true) {
                XmlUtils.nextElement(parser);
                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
                    break;
                }

                String name = parser.getName();
                if ("group".equals(name)) {
                    // .....
                } else if ("permission".equals(name)) {
                    // .....

                } else if ("assign-permission".equals(name)) {
                    // .....

                } else if ("library".equals(name)) {
					// .....

                } else if ("feature".equals(name)) {
                    String fname = parser.getAttributeValue(null, "name");
                    if (fname == null) {
                        Slog.w(TAG, " without name at "
                                + parser.getPositionDescription());
                    } else {
                        //Log.i(TAG, "Got feature " + fname);
                        FeatureInfo fi = new FeatureInfo();
                        fi.name = fname;
                        mAvailableFeatures.put(fname, fi);
                    }
                    XmlUtils.skipCurrentTag(parser);
                    continue;

                } else {
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                }

            }
            permReader.close();
        } catch (XmlPullParserException e) {
            Slog.w(TAG, "Got execption parsing permissions.", e);
        } catch (IOException e) {
            Slog.w(TAG, "Got execption parsing permissions.", e);
        }
    }

结合刚才说的注释,就去检查etc/permisions.xml里面有没有关于widget的feature咯,这个feature的字符串可以从PackageManager里面可以看到是“android.software.app_widgets”。

取出/system/etc/permissions.xml文件一搜,果真没有这个feature,同时也检查了etc目录下其他xml文件,都没有这个feature。

那么现在要做的就是增加这个feature,在permisions.xml中追加如下内容,也可以弄成单独xml放到etc目录


    

将文件push进去之后再次创建widget,Bingo!, allocateAppWidgetId返回不是-1啦,widget也创建成功了~~~


【原创文章,转载请声明】转自http://blog.csdn.net/allen_704/article/details/28640827


你可能感兴趣的:(android)