Android 8.0 (34) - - Android 8.0 Settings Process Analysis and Change

Keywords: Android Java xml Fragment

Android 8.0 Settings Process Analysis and Change


One, compared to Android Settings 7.0

As shown below, on the basis of 7.0, the new side-slip menu of 7.0 has been removed (maybe it feels like chicken ribs). Adding an additional level of page, the original category title into the first level of menu sub-items. The code architecture is also slightly changed, and LifeCycle (Life Cycle Awareness, not covered in this article) is introduced as an architectural component.


Second, the loading of the first level menu

Looking at the source code, most of us start with Android Manifest. xml, which is not an exception this time.

packages\apps\Settings\AndroidManifest.xml:

  1. <activity-alias android:name="Settings"  
  2.                 android:taskAffinity="com.android.settings"  
  3.                 android:label="@string/settings_label_launcher"  
  4.                 android:launchMode="singleTask"  
  5.                 android:targetActivity="Settings">  
  6.             <intent-filter>  
  7.                 <action android:name="android.intent.action.MAIN" />  
  8.                 <category android:name="android.intent.category.DEFAULT" />  
  9.                 <category android:name="android.intent.category.LAUNCHER" />  
  10.             </intent-filter>  
  11.             <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/>  
  12.         </activity-alias>  

Find the class < category android: name = "android. intent. category. LAUNCHER" /> belongs to, Settings.java. But when you open the Settings.java class, there's nothing but a large number of static classes that inherit SettingsActivity. Then go to the parent class SettingsActivity.java.

packages\apps\Settings\src\com\android\settings\SettingsActivity.java:

The first, of course, is onCreate()->.

  1. @Override  
  2.     protected void onCreate(Bundle savedState) {  
  3.         super.onCreate(savedState);  
  4.         long startTime = System.currentTimeMillis();  
  5.         //Factory class implementation method com.android.settings.overlay.FeatureFactoryImpl.java  
  6.         final FeatureFactory factory = FeatureFactory.getFactory(this);  
  7.         //The factory class for getting menu information is Dashboard Feature ProviderImpl. Java  
  8.         mDashboardFeatureProvider = factory.getDashboardFeatureProvider(this);  
  9.         mMetricsFeatureProvider = factory.getMetricsFeatureProvider();  
  10.         //Get the value of <meta-data/> label "com.android.settings.FRAGMENT_CLASS" from intent information (class name for loading Fragment below)  
  11.         getMetaData();  
  12.         ... ...  
  13.         //Get the class name from getMetaData() above  
  14.         final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);  
  15.         //Is it a shortcut entry (for example, entering a Settings item from another application)  
  16.         mIsShortcut = isShortCutIntent(intent) || isLikeShortCutIntent(intent) ||  
  17.                 intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, false);  
  18.         ... ...  
  19.         //Is the current class Settings.class, that is, the way to enter the main settings interface by clicking on the icon on the launcher  
  20.         mIsShowingDashboard = className.equals(Settings.class.getName());  
  21.         ... ...  
  22.         setContentView(mIsShowingDashboard ?  
  23.                 R.layout.settings_main_dashboard : R.layout.settings_main_prefs);  
  24.         mContent = findViewById(R.id.main_content);  
  25.         getFragmentManager().addOnBackStackChangedListener(this);  
  26.         if (savedState != null) {  
  27.           ... ...  
  28.         } else {  
  29.             //Loading layout  
  30.             launchSettingFragment(initialFragmentName, isSubSettings, intent);  
  31.         }  
  32.   
  33.         ... ...  
  34.     }  


launchSettingFragment()->

  1.  @VisibleForTesting  
  2.     void launchSettingFragment(String initialFragmentName, boolean isSubSettings, Intent intent) {  
  3.         if (!mIsShowingDashboard && initialFragmentName != null) {  
  4.             ... ...  
  5.             switchToFragment(initialFragmentName, initialArguments, truefalse,  
  6.                 mInitialTitleResId, mInitialTitle, false);  
  7.         } else {  
  8.             // Show search icon as up affordance if we are displaying the main Dashboard  
  9.             mDisplayHomeAsUpEnabled = true;  
  10.             mInitialTitleResId = R.string.dashboard_title;  
  11.             //Go to the home page and replace the target < span style= "font-size: 12px;" > Fragment</span>  
  12.             switchToFragment(DashboardSummary.class.getName(), null /* args */falsefalse,  
  13.                 mInitialTitleResId, mInitialTitle, false);  
  14.         }  
  15.     }  

Continue, let's look at Dashboard Summary. java, for which we mainly want to know how it loads its data and how it loads its subitems.

packages\apps\Settings\src\com\android\settings\dashboard\DashboardSummary.java:

Data acquisition for subitems is implemented in updateCategory AndSuggestion ().

  1. @VisibleForTesting  
  2.     void updateCategoryAndSuggestion(List<Tile> suggestions) {  
  3.         final Activity activity = getActivity();  
  4.         if (activity == null) {  
  5.             return;  
  6.         }  
  7.         /*Query subitem data according to the value of "com.android.settings.category", where the value is "com.android.settings.category.ia.homepage". 
  8.         Specific acquisitions are traced to frameworks base packages SettingsLib src com android settingslib drawer TileUtils. java. 
  9.         Query through PackageManager for all classes that contain the value defined in AndroidManifest.xml as <meta-data/>. Note: Data from non-system applications will be filtered out! 
  10.         Interested self-study, not in-depth study here.*/  
  11.         final DashboardCategory category = mDashboardFeatureProvider.getTilesForCategory(  
  12.                 CategoryKey.CATEGORY_HOMEPAGE);  
  13.         if (category == null) {  
  14.             return;  
  15.         }  
  16.         mSummaryLoader.updateSummaryToCache(category);  
  17.         if (suggestions != null) {  
  18.             mAdapter.setCategoriesAndSuggestions(category, suggestions);  
  19.         } else {  
  20.             //Data binding in adapter, -> packages apps Settings src com android settings dashboard Dashboard Adapter.java  
  21.             mAdapter.setCategory(category);  
  22.         }  
  23.     }  

For the first level menu loading. The configuration in AndroidManifest.xml is as follows:


Loading of Level 2 Menu

Above all, we know that the first level menu is completely dynamic loading, but the second level menu is dynamic loading and static xml layout file, take "system" as an example.

packages\apps\Settings\AndroidManifest.xml:

  1. <activity android:name=".Settings$SystemDashboardActivity"  
  2.                   android:label="@string/header_category_system"  
  3.                   android:icon="@drawable/ic_settings_about">  
  4.             <intent-filter android:priority="-1">  
  5.                 <action android:name="com.android.settings.action.SETTINGS"/>  
  6.             </intent-filter>  
  7.             <meta-data android:name="com.android.settings.category"  
  8.                        android:value="com.android.settings.category.ia.homepage"/>  
  9.             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"  
  10.                        android:value="com.android.settings.system.SystemDashboardFragment"/>  
  11.             <meta-data android:name="com.android.settings.summary"  
  12.                        android:resource="@string/system_dashboard_summary"/>  
  13.         </activity>  

System Dashboard Fragment. Java inherits Dashboard Fragment. java. We mainly look at this category.

packages\apps\Settings\src\com\android\settings\dashboard\DashboardFragment.java:

1. Static loading part:

The static loading part is implemented by displayResourceTiles ()->.

  1. /** 
  2.     * Displays resource based tiles. 
  3.     */  
  4.    private void displayResourceTiles() {  
  5.     //Get the id of the xml layout file (Dashboard Fragment. Java implements this method)  
  6.        final int resId = getPreferenceScreenResId();  
  7.        if (resId <= 0) {  
  8.            return;  
  9.        }  
  10.        addPreferencesFromResource(resId);  
  11.        final PreferenceScreen screen = getPreferenceScreen();  
  12.     /** Implementing Business Logic of Subitem Control in Layout File 
  13.      *  DashboardFragment.java A subclass implements the getPreferenceControllers () method, which loads the implementation business logic class inherited from AbstractPreferenceController.java 
  14.      */  
  15.        Collection<AbstractPreferenceController> controllers = mPreferenceControllers.values();  
  16.        for (AbstractPreferenceController controller : controllers) {  
  17.            controller.displayPreference(screen);  
  18.        }  
  19.    }  

2. Dynamic loading part:

The implementation method of dynamic loading part refresh Dashboard Tiles ()->

  1. /** 
  2.      * Refresh preference items backed by DashboardCategory. 
  3.      */  
  4.     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)  
  5.     void refreshDashboardTiles(final String TAG) {  
  6.         final PreferenceScreen screen = getPreferenceScreen();  
  7.         /* Get subitems 
  8.          * getCategoryKey()Get the Category value from Dashboard Fragment Registry. PARENT_TO_CATEGORY_KEY_MAP. 
  9.          * This value is obtained by class name 
  10.          * Storage: PARENT_TO_CATEGORY_KEY_MAP.put (System Dashboard Fragment. class. getName (), Category Key. CATEGORY_SYSTEM); 
  11.          * CATEGORY_SYSTEM = "com.android.settings.category.ia.system"; 
  12.          */  
  13.         final DashboardCategory category =  
  14.                 mDashboardFeatureProvider.getTilesForCategory(getCategoryKey());  
  15.         ... ...  
  16.         // Install dashboard tiles.  
  17.         for (Tile tile : tiles) {  
  18.             ... ...  
  19.             if (mDashboardTilePrefKeys.contains(key)) {  
  20.                 ... ...  
  21.             } else {  
  22.                 // Don't have this key, add it.  
  23.                 final Preference pref = new Preference(getPrefContext());  
  24.                 /*Bind and load here 
  25.                  *packages\apps\Settings\src\com\android\settings\dashboard\DashboardFeatureProviderImpl.java->bindPreferenceToTile() 
  26.                  */  
  27.                 mDashboardFeatureProvider.bindPreferenceToTile(getActivity(), getMetricsCategory(),  
  28.                         pref, tile, key, mPlaceholderPreferenceController.getOrder());  
  29.                 mProgressiveDisclosureMixin.addPreference(screen, pref);  
  30.                 mDashboardTilePrefKeys.add(key);  
  31.             }  
  32.             remove.remove(key);  
  33.         }  
  34.         // Finally remove tiles that are gone.  
  35.         for (String key : remove) {  
  36.             mDashboardTilePrefKeys.remove(key);  
  37.             mProgressiveDisclosureMixin.removePreference(screen, key);  
  38.         }  
  39.         mSummaryLoader.setListening(true);  
  40.     }  

This is almost the end of the Settings loading process.

Fourth, by the way

Pull down the menu bar for a long time and press the settings Icon to enter the settings. There will be an additional "System Interface Adjustment Tool" in the system item. So how does this show and hide?

frameworks\base\packages\SystemUI\src\com\android\systemui\tuner\TunerService.java

->setTunerEnabled():

  1. public static final void setTunerEnabled(Context context, boolean enabled) {  
  2.         //This method can also be used to hide application icons and start a component.  
  3.         userContext(context).getPackageManager().setComponentEnabledSetting(  
  4.                 new ComponentName(context, TunerActivity.class),  
  5.                 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED  
  6.                         : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,  
  7.                 PackageManager.DONT_KILL_APP);  
  8.     }  

Posted by felodiaz on Sat, 18 May 2019 10:26:26 -0700