Android S版本MtkSettings的加载流程(二)

在上一篇 Android S版本MtkSettings的加载流程(一) 我们介绍了MtkSettings从启动到加载的一个流程。这一篇主要记录设置项prefrence的两种加载方式:静态加载和动态加载

两种加载方式

主页TopLevelSettings.java和二级菜单页都继承于DashboardFragment.java,设置项加载方式的入口都是从DashboardFragment.java开始的。

Fragment
PreferenceFragmentCompat
ObservablePreferenceFragment
InstrumentedPreferenceFragment
SettingsPreferenceFragment
DashboardFragment
NetworkDashboardFragment
ConnectedDeviceDashboardFragment
其它二级页面OtherSubFragment

网络和互联网:NetworkDashboardFragment.java实现了父类DashboardFragment.java的getPreferenceScreenResId()方法获取xml布局。
它是一个抽象方法,需要每个子类Fragment设置自己的布局文件。

getPreferenceScreenResId()方法的调用链关系如下:

onCreate
override
extends
invoke
invoke
invoke
PreferenceFragmentCompat类
abstract onCreatePreferences方法
DashboardFragment类
refreshAllPreferences方法
displayResourceTiles方法
refreshDashboardTiles方法

重点来了,DashboardFragment类通过调用displayResourceTiles()方法从xml资源文件中静态加载显示preference,从refreshDashboardTiles()方法中动态加载显示preference。

	/**
     * Refresh all preference items, including both static prefs from xml, and dynamic items from
     * DashboardCategory.
     */
    private void refreshAllPreferences(final String tag) {
    
    
        final PreferenceScreen screen = getPreferenceScreen();
        // First remove old preferences.
        if (screen != null) {
    
    
            // Intentionally do not cache PreferenceScreen because it will be recreated later.
            screen.removeAll();
        }

        // Add resource based tiles.
        displayResourceTiles();

        refreshDashboardTiles(tag);

        final Activity activity = getActivity();
        if (activity != null) {
    
    
            Log.d(tag, "All preferences added, reporting fully drawn");
            activity.reportFullyDrawn();
        }

        updatePreferenceVisibility(mPreferenceControllers);
    }

1. 静态方式加载preference

	/**
     * Displays resource based tiles.
     */
    private void displayResourceTiles() {
    
    
        final int resId = getPreferenceScreenResId();
        if (resId <= 0) {
    
    
            return;
        }
        addPreferencesFromResource(resId);
        final PreferenceScreen screen = getPreferenceScreen();
        screen.setOnExpandButtonClickListener(this);
        displayResourceTilesToScreen(screen);
    }

2. 动态方式加载preference

	/**
     * Refresh preference items backed by DashboardCategory.
     */
    private void refreshDashboardTiles(final String tag) {
    
    
        final PreferenceScreen screen = getPreferenceScreen();

		//[android]获得子菜单所属类别Category
        final DashboardCategory category =
                mDashboardFeatureProvider.getTilesForCategory(getCategoryKey());
        if (category == null) {
    
    
            Log.d(tag, "NO dashboard tiles for " + tag);
            return;
        }
		//[android]获得该类别Category下的所有菜单项
        final List<Tile> tiles = category.getTiles();
        if (tiles == null) {
    
    
            Log.d(tag, "tile list is empty, skipping category " + category.key);
            return;
        }
        // Create a list to track which tiles are to be removed.
        final Map<String, List<DynamicDataObserver>> remove = new ArrayMap(mDashboardTilePrefKeys);

        // Install dashboard tiles.
        final boolean forceRoundedIcons = shouldForceRoundedIcon();
        for (Tile tile : tiles) {
    
    
			//[android]获得菜单项tile所属的key:如果未配置meta标签name为"com.android.settings.keyhint"的属性,则将class name拼接处理
            final String key = mDashboardFeatureProvider.getDashboardKeyForTile(tile);
            if (TextUtils.isEmpty(key)) {
    
    
                Log.d(tag, "tile does not contain a key, skipping " + tile);
                continue;
            }
			//[android]过滤不需要显示的tile
            if (!displayTile(tile)) {
    
    
                continue;
            }
            if (mDashboardTilePrefKeys.containsKey(key)) {
    
    
                // Have the key already, will rebind.
                final Preference preference = screen.findPreference(key);
                mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(getActivity(),
                        forceRoundedIcons, getMetricsCategory(), preference, tile, key,
                        mPlaceholderPreferenceController.getOrder());
            } else {
    
    
                // Don't have this key, add it.
                //[android]根据tile类型创建首选项Preference
                final Preference pref = createPreference(tile);
				//[android]将Preference与Tile提供的数据绑定,并获取动态数据观察者
                final List<DynamicDataObserver> observers =
                        mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(getActivity(),
                                forceRoundedIcons, getMetricsCategory(), pref, tile, key,
                                mPlaceholderPreferenceController.getOrder());
                screen.addPreference(pref);
				//[android]注册监听URI数据:title,summary,switch状态变化
                registerDynamicDataObservers(observers);
                mDashboardTilePrefKeys.put(key, observers);
            }
            remove.remove(key);
        }
        // Finally remove tiles that are gone.
        for (Map.Entry<String, List<DynamicDataObserver>> entry : remove.entrySet()) {
    
    
            final String key = entry.getKey();
            mDashboardTilePrefKeys.remove(key);
            final Preference preference = screen.findPreference(key);
            if (preference != null) {
    
    
                screen.removePreference(preference);
            }
            unregisterDynamicDataObservers(entry.getValue());
        }
    }   

动态加载流程

即refreshDashboardTiles()方法的流程,首先关注方法mDashboardFeatureProvider.getTilesForCategory(getCategoryKey());

  • getCategoryKey()

     /**
      * Returns the CategoryKey for loading {@link DashboardCategory} for this fragment.
      */
     @VisibleForTesting
     public String getCategoryKey() {
          
          
         return DashboardFragmentRegistry.PARENT_TO_CATEGORY_KEY_MAP.get(getClass().getName());
     }
    

    DashboardFragmentRegistry类在静态块中初始化了PARENT_TO_CATEGORY_KEY_MAP键值对象

    static {
          
          
       PARENT_TO_CATEGORY_KEY_MAP = new ArrayMap<>();
       PARENT_TO_CATEGORY_KEY_MAP.put(TopLevelSettings.class.getName(),
               CategoryKey.CATEGORY_HOMEPAGE);
       PARENT_TO_CATEGORY_KEY_MAP.put(
               NetworkDashboardFragment.class.getName(), CategoryKey.CATEGORY_NETWORK);
       //省略...
    }
    

    CategoryKey类定义多种category类别

    // Activities in this category shows up in Settings homepage.
    public static final String CATEGORY_HOMEPAGE = "com.android.settings.category.ia.homepage";
    // Top level category.
    public static final String CATEGORY_NETWORK = "com.android.settings.category.ia.wireless";
    //省略各种category定义
    

    此方法getCategoryKey()是获取fragment的CategoryKey用于动态加载,比如主界面TopLevelSettings.java的key为"com.android.settings.category.ia.homepage"。网络和互联网界面NetworkDashboardFragment.java的key为"com.android.settings.category.ia.wireless"。

  • getTilesForCategory()

    getTilesForCategory方法的具体实现在DashboardFeatureProviderImpl.java中

    @Override
    public DashboardCategory getTilesForCategory(String key) {
          
          
       	return mCategoryManager.getTilesByCategory(mContext, key);
    }
    

    CategoryManager.java的getTilesByCategory()方法:

    public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey) {
          
          
        tryInitCategories(context);
        return mCategoryByKeyMap.get(categoryKey);
    }	
    

  • tryInitCategories()

    getTilesByCategory()方法返回值是通过categoryKey去mCategoryByKeyMap集合中寻找并返回DashboardCategory对象,那么tryInitCategories()方法应该会存在加载配置项然后对mCategoryByKeyMap赋值的操作。

    private synchronized void tryInitCategories(Context context) {
          
          
        // Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange
        // happens.
        tryInitCategories(context, false /* forceClearCache */);
    }
    
    private synchronized void tryInitCategories(Context context, boolean forceClearCache) {
          
          
        if (mCategories == null) {
          
          
            final boolean firstLoading = mCategoryByKeyMap.isEmpty();
            if (forceClearCache) {
          
          
                mTileByComponentCache.clear();
            }
    		//清空mCategoryByKeyMap集合
            mCategoryByKeyMap.clear();
    		//查询构建DashboardCategory的list集合
            mCategories = TileUtils.getCategories(context, mTileByComponentCache);
    		//遍历list填充mCategoryByKeyMap集合;
            for (DashboardCategory category : mCategories) {
          
          
                mCategoryByKeyMap.put(category.key, category);
            }
    		//使用最新的category keys去替换旧的category keys
            backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
    		//根据PackageName排序Categories
            sortCategories(context, mCategoryByKeyMap);
    		//去掉category中重复的tiles
            filterDuplicateTiles(mCategoryByKeyMap);
            if (firstLoading) {
          
          
                logTiles(context);
            }
        }
    }
    

    主要还是查询构建DashboardCategory的list集合的逻辑,即TileUtils.getCategories()这个方法去获取相关数据。

  • getCategories()

    源码:frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java

     /**
      * Build a list of DashboardCategory.
      */
     public static List<DashboardCategory> getCategories(Context context,
             Map<Pair<String, String>, Tile> cache) {
          
          
         final long startTime = System.currentTimeMillis();
     	//[android]是否完成开机向导设置
         final boolean setup =
                 Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0) != 0;
         final ArrayList<Tile> tiles = new ArrayList<>();
         final UserManager userManager = (UserManager) context.getSystemService(
                 Context.USER_SERVICE);
     	//[android]遍历所有用户,调用loadTilesForAction()方法根据相关action获取相关tiles,填充tiles集合
         for (UserHandle user : userManager.getUserProfiles()) {
          
          
             // TODO: Needs much optimization, too many PM queries going on here.
             if (user.getIdentifier() == ActivityManager.getCurrentUser()) {
          
          
                 // Only add Settings for this user.
                 loadTilesForAction(context, user, SETTINGS_ACTION, cache, null, tiles, true);
                 loadTilesForAction(context, user, OPERATOR_SETTINGS, cache,
                         OPERATOR_DEFAULT_CATEGORY, tiles, false);
                 loadTilesForAction(context, user, MANUFACTURER_SETTINGS, cache,
                         MANUFACTURER_DEFAULT_CATEGORY, tiles, false);
             }
             if (setup) {
          
          
                 loadTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false);
                 loadTilesForAction(context, user, IA_SETTINGS_ACTION, cache, null, tiles, false);
             }
         }
    
     	 //[android]新建categoryMap集合,key为categoryKey,value为DashboardCategory对象
         final HashMap<String, DashboardCategory> categoryMap = new HashMap<>();
         for (Tile tile : tiles) {
          
          
             final String categoryKey = tile.getCategory();
             DashboardCategory category = categoryMap.get(categoryKey);
             if (category == null) {
          
          
                 category = new DashboardCategory(categoryKey);
    
                 if (category == null) {
          
          
                     Log.w(LOG_TAG, "Couldn't find category " + categoryKey);
                     continue;
                 }
                 categoryMap.put(categoryKey, category);
             }
             category.addTile(tile);
         }
    
         final ArrayList<DashboardCategory> categories = new ArrayList<>(categoryMap.values());
         for (DashboardCategory category : categories) {
          
          
     		//[android]对Tiles按照priority从大到小排序:Collections.sort(mTiles, Tile.TILE_COMPARATOR);
             category.sortTiles();
         }
         if (DEBUG_TIMING) {
          
          
             Log.d(LOG_TAG, "getCategories took "
                     + (System.currentTimeMillis() - startTime) + " ms");
         }
         return categories;
     }
    

    getCategories()方法新建tiles集合,遍历设备中所有用户,调用getTilesForAction()方法根据相关action分别从Activity和Provider两种ComponentInfo中获取Tile,最后填充tiles集合。

  • getTilesForAction()和loadTile()

    设置中主要通过这些action去搜索系统中符合的组件去作为菜单项的Tile。

    @VisibleForTesting
    static void loadTilesForAction(Context context,
            UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache,
            String defaultCategory, List<Tile> outTiles, boolean requireSettings) {
          
          
        final Intent intent = new Intent(action);
        if (requireSettings) {
          
          
            intent.setPackage(SETTING_PKG);
        }
    	//[android]分别从Activity和Provider两种ComponentInfo中获取Tile
        loadActivityTiles(context, user, addedCache, defaultCategory, outTiles, intent);
        loadProviderTiles(context, user, addedCache, defaultCategory, outTiles, intent);
    }
    
    private static void loadActivityTiles(Context context,
            UserHandle user, Map<Pair<String, String>, Tile> addedCache,
            String defaultCategory, List<Tile> outTiles, Intent intent) {
          
          
        final PackageManager pm = context.getPackageManager();
        final List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
                PackageManager.GET_META_DATA, user.getIdentifier());
        for (ResolveInfo resolved : results) {
          
          
            if (!resolved.system) {
          
          
                // Do not allow any app to add to settings, only system ones.
                continue;
            }
            final ActivityInfo activityInfo = resolved.activityInfo;
            final Bundle metaData = activityInfo.metaData;
            loadTile(user, addedCache, defaultCategory, outTiles, intent, metaData, activityInfo);
        }
    }
    

    最终都会调用到loadTile()方法的逻辑:通过PackageManager服务从清单文件的Activity和Provider两种ComponentInfo中提取Tile信息。

    private static void loadTile(UserHandle user, Map<Pair<String, String>, Tile> addedCache,
             String defaultCategory, List<Tile> outTiles, Intent intent, Bundle metaData,
             ComponentInfo componentInfo) {
          
          
         // Skip loading tile if the component is tagged primary_profile_only but not running on
         // the current user.
         if (user.getIdentifier() != ActivityManager.getCurrentUser()
                 && Tile.isPrimaryProfileOnly(componentInfo.metaData)) {
          
          
             Log.w(LOG_TAG, "Found " + componentInfo.name + " for intent "
                     + intent + " is primary profile only, skip loading tile for uid "
                     + user.getIdentifier());
             return;
         }
     	//[android]解析AndroidManifest.xml meta标签中key="com.android.settings.category"的值
         String categoryKey = defaultCategory;
         // Load category
         if ((metaData == null || !metaData.containsKey(EXTRA_CATEGORY_KEY))
                 && categoryKey == null) {
          
          
             Log.w(LOG_TAG, "Found " + componentInfo.name + " for intent "
                     + intent + " missing metadata "
                     + (metaData == null ? "" : EXTRA_CATEGORY_KEY));
             return;
         } else {
          
          
             categoryKey = metaData.getString(EXTRA_CATEGORY_KEY);
         }
    
         final boolean isProvider = componentInfo instanceof ProviderInfo;
         final Pair<String, String> key = isProvider
                 ? new Pair<>(((ProviderInfo) componentInfo).authority,
                         metaData.getString(META_DATA_PREFERENCE_KEYHINT))
                 : new Pair<>(componentInfo.packageName, componentInfo.name);
     	//[android]构建具体的tile对象,比如ActivityTile,包含ComponentInfo和categoryKey
         Tile tile = addedCache.get(key);
         if (tile == null) {
          
          
             tile = isProvider
                     ? new ProviderTile((ProviderInfo) componentInfo, categoryKey, metaData)
                     : new ActivityTile((ActivityInfo) componentInfo, categoryKey);
             addedCache.put(key, tile);
         } else {
          
          
             tile.setMetaData(metaData);
         }
    
         if (!tile.userHandle.contains(user)) {
          
          
             tile.userHandle.add(user);
         }
     	//[android]将搜集到的tile对象添加到outTiles集合内并输出
         if (!outTiles.contains(tile)) {
          
          
             outTiles.add(tile);
         }
     }
    

构建的Tile对象从AndroidManifest.xml meta-data配置中动态获取了哪些信息?

  • 优先级order:META_DATA_KEY_ORDER = “com.android.settings.order”
   /**
     * Priority of this tile, used for display ordering.
     */
    public int getOrder() {
    
    
        if (hasOrder()) {
    
    
            return mMetaData.getInt(META_DATA_KEY_ORDER);
        } else {
    
    
            return 0;
        }
    }
  • 是否有switch控制开关:META_DATA_PREFERENCE_SWITCH_URI = “com.android.settings.switch_uri”
	/**
     * Check whether tile has a switch.
     */
    public boolean hasSwitch() {
    
    
        return mMetaData != null && mMetaData.containsKey(META_DATA_PREFERENCE_SWITCH_URI);
    }
  • 标题Title:META_DATA_PREFERENCE_TITLE = “com.android.settings.title”
title = mMetaData.getString(META_DATA_PREFERENCE_TITLE);
// Set the preference title by the component if no meta-data is found
if (title == null) {
    
    
	title = getComponentLabel(context);
}
  • 摘要Summary:META_DATA_PREFERENCE_SUMMARY = “com.android.settings.summary”
summary = mMetaData.getString(META_DATA_PREFERENCE_SUMMARY);
  • 图标Icon:META_DATA_PREFERENCE_ICON = “com.android.settings.icon”
	int iconResId = mMetaData.getInt(META_DATA_PREFERENCE_ICON);
	// Set the icon. Skip the transparent color for backward compatibility since Android S.        
	if (iconResId != 0 && iconResId != android.R.color.transparent) {
    
    
    	final Icon icon = Icon.createWithResource(componentInfo.packageName, iconResId);        
		if (isIconTintable(context)) {
    
    
    		final TypedArray a = context.obtainStyledAttributes(new int[]{
    
    
                        android.R.attr.colorControlNormal});
        	final int tintColor = a.getColor(0, 0);
        	a.recycle();
        	icon.setTint(tintColor);                   
    	}
    	return icon;
    } else {
    
    
         return null;
    }                 
  • 唯一标识Key:META_DATA_PREFERENCE_KEYHINT = “com.android.settings.keyhint”
/**
 - Optional key to use for this tile.
 */
public String getKey(Context context) {
    
    
    if (!hasKey()) {
    
    
        return null;
    }
    ensureMetadataNotStale(context);
    if (mMetaData.get(META_DATA_PREFERENCE_KEYHINT) instanceof Integer) {
    
    
        return context.getResources().getString(mMetaData.getInt(META_DATA_PREFERENCE_KEYHINT));
    } else {
    
    
        return mMetaData.getString(META_DATA_PREFERENCE_KEYHINT);
    }
}

当清单文件的meta-data没有配置key时,Tile对象的key是什么值?

DashboardFeatureProviderImpl.getDashboardKeyForTile()首先判断AndroidManifest.xml中是否配置了meta-data标签name为"com.android.settings.keyhint"的属性;
如果未配置该属性,则通过将class name拼接处理:DASHBOARD_TILE_PREF_KEY_PREFIX + getClassName(),即"dashboard_tile_pref_" + classname

@Override
public String getDashboardKeyForTile(Tile tile) {
    
    
    if (tile == null) {
    
    
        return null;
    }
    if (tile.hasKey()) {
    
    
        return tile.getKey(mContext);
    }
    final StringBuilder sb = new StringBuilder(DASHBOARD_TILE_PREF_KEY_PREFIX);
    final ComponentName component = tile.getIntent().getComponent();
    sb.append(component.getClassName());
    return sb.toString();
}

当清单文件的meta-data数据发生变更时,preference如何及时更新?

通过refreshDashboardTiles()中的bindPreferenceToTileAndGetObservers()方法。

@Override
public List<DynamicDataObserver> bindPreferenceToTileAndGetObservers(FragmentActivity activity,
        boolean forceRoundedIcon, int sourceMetricsCategory, Preference pref, Tile tile,
        String key, int baseOrder) {
    
    
    if (pref == null) {
    
    
        return null;
    }
    if (!TextUtils.isEmpty(key)) {
    
    
        pref.setKey(key);
    } else {
    
    
        pref.setKey(getDashboardKeyForTile(tile));
    }
    final List<DynamicDataObserver> outObservers = new ArrayList<>();
    DynamicDataObserver observer = bindTitleAndGetObserver(pref, tile);
    if (observer != null) {
    
    
        outObservers.add(observer);
    }
    observer = bindSummaryAndGetObserver(pref, tile);
    if (observer != null) {
    
    
        outObservers.add(observer);
    }
    observer = bindSwitchAndGetObserver(pref, tile);
    if (observer != null) {
    
    
        outObservers.add(observer);
    }
	//以下代码省略
}

bindTitleAndGetObserver、bindSummaryAndGetObserver、bindSwitchAndGetObserver方法分别对标题、摘要、switch开关状态进行了绑定监听,它们最终都调用了createDynamicDataObserver()方法进行异步刷新。

private DynamicDataObserver createDynamicDataObserver(String method, Uri uri, Preference pref) {
    
    
     return new DynamicDataObserver() {
    
    
         @Override
         public Uri getUri() {
    
    
             return uri;
         }

         @Override
         public void onDataChanged() {
    
    
             switch (method) {
    
    
                 case METHOD_GET_DYNAMIC_TITLE:
                     refreshTitle(uri, pref);
                     break;
                 case METHOD_GET_DYNAMIC_SUMMARY:
                     refreshSummary(uri, pref);
                     break;
                 case METHOD_IS_CHECKED:
                     refreshSwitch(uri, pref);
                     break;
             }
         }
     };
 }

通过以上一系列流程,设置项Preference就从AndroidManifest.xml文件meta-data标签属性中加载出来了。以Settings对“系统-开发者选项“的配置项为例:

<activity
    android:name="Settings$DevelopmentSettingsDashboardActivity"
    <!--若meta-data中无定义com.android.settings.title,则取lable为preference标题-->
    android:label="@string/development_settings_title"
    android:icon="@drawable/ic_settings_development"
    android:exported="true"
    android:enabled="false">
    <intent-filter android:priority="1">
        <action android:name="android.settings.APPLICATION_DEVELOPMENT_SETTINGS" />
        <action android:name="com.android.settings.APPLICATION_DEVELOPMENT_SETTINGS" />
        <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/>
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    <intent-filter>
    	<!--通过TileUtils.loadActivityTiles()方法可以被Settings搜索到的action-->
        <action android:name="com.android.settings.action.SETTINGS" />
    </intent-filter>
    <!--preference根据order值显示优先级-->
    <meta-data android:name="com.android.settings.order" android:value="-40"/>
    <!--类别,表示显示在SystemDashboardFragment中,DashboardFragmentRegistry.java有定义-->
    <meta-data android:name="com.android.settings.category"
               android:value="com.android.settings.category.ia.system" />
    <!--preference摘要-->
    <meta-data android:name="com.android.settings.summary"
               android:resource="@string/summary_empty"/>
    <!--preference图标-->
    <meta-data android:name="com.android.settings.icon"
               android:resource="@drawable/ic_settings_development" />
    <!--preference点击跳转的fragment:DevelopmentSettingsDashboardFragment-->
    <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
               android:value="com.android.settings.development.DevelopmentSettingsDashboardFragment" />
    <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
               android:value="true" />
</activity>

实践案例

1、将第三方应用(系统升级)页面动态添加为Settings首页的一级菜单
在这里插入图片描述
在系统升级应用清单文件添加如下配置即可:

<activity
	<intent-filter android:priority="5">
        <action android:name="com.android.settings.action.EXTRA_SETTINGS" />
    </intent-filter>
    <meta-data
        android:name="com.android.settings.category"
        android:value="com.android.settings.category.ia.homepage" />
    <meta-data
        android:name="com.android.settings.icon"
        android:resource="@drawable/ic_settings_applications" />
    <meta-data
        android:name="com.android.settings.summary"
        android:resource="@string/auto_check" />
</activity>

2、将Settings“系统-开发者选项-系统跟踪”菜单项去掉

系统跟踪界面来源于系统应用Traceur,对应的Activity为:com.android.traceur/.MainActivity

该Activity的meta-data中没有定义"com.android.settings.keyhint"的属性,根据getDashboardKeyForTile()的规则得出该Tile对应的key为:“dashboard_tile_pref_com.android.traceur.MainActivity”。

由此我们扩展下DashboardFragment.displayTile()方法,同时把该key加入到mSuppressInjectedTileKeys定义的list集合中。具体修改如下:

protected boolean displayTile(Tile tile) {
    
    
	if (mSuppressInjectedTileKeys != null && tile.hasKey()) {
    
    
	    // For suppressing injected tiles for OEMs.
	    return !mSuppressInjectedTileKeys.contains(tile.getKey(getContext()));
	}
	//add by liuke
	if (mSuppressInjectedTileKeys != null) {
    
    
	    String key = mDashboardFeatureProvider.getDashboardKeyForTile(tile);
	    return !mSuppressInjectedTileKeys.contains(key);
	}
	//end by liuke
	return true;
}

猜你喜欢

转载自blog.csdn.net/qq_23069607/article/details/127394798