美文网首页我爱编程
魅族Android7.0 Settings源码分析

魅族Android7.0 Settings源码分析

作者: Ucoon | 来源:发表于2018-05-27 18:58 被阅读202次

    前言:

    只能说对魅族手机系统很是无奈啊!!!为了分析魅族手机无法通过常见的方法跳到系统设置的无障碍服务,只好通过豌豆荚将settings.apk导出然后进行反编译,跟踪源码.......

    准备工作(反编译apk以及AndroidManifest.xml文件)

    1. 从反编译一开始就碰上了坑,利用dex2jar-2.0无法导出classes-dex2jar.jar文件,原因暂未找到,解决方案是将classes.dex用nodepad++打开,将037,改成036,保存,再用dex2jar。

    参考链接:https://www.jianshu.com/p/55bf5f688e9a

    1. 反编译AndroidManifest.xml文件可请教谷歌

    Settings应用的启动类

    首先跟踪Settings的启动类,查看package/app/Settings/AndroidManifest.xml文件

           <activity-alias android:label="@string/settings_label_launcher" android:launchMode="singleTask" android:name="com.android.settings.Settings" android:targetActivity="com.android.settings.Settings" android:taskAffinity="com.android.settings">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity-alias>
    

    第一次遇到<activity-alias>标签,一脸懵逼o((⊙﹏⊙))o,查了才知道是作为一个已存在Activity的别名,可用来设置某个Activity的快捷入口。举例:某个Activity需要进入应用的主界面才能够点击进入,如果使用了该标签,甚至可以在桌面生成一个该Activity的图标,然后点击桌面图标直接进入该Activity。
    从AndroidManifest.xml可以看到,Settings的启动类为Settings.java,源码如下:

    public class Settings extends SettingsActivity
    {
      public static class AccessibilityDaltonizerSettingsActivity
        extends SettingsActivity
      {}
      
      public static class AccessibilitySettingsActivity
        extends SettingsActivity
      {}
      
      public static class AccountSettingsActivity
        extends SettingsActivity
      {}
      
      public static class AccountSyncSettingsActivity
        extends SettingsActivity
      {}
      
      public static class AdvancedAppsActivity
        extends SettingsActivity
      {}
      
      public static class AdvancedWifiSettingsActivity
        extends SettingsActivity
      {}
      
      public static class AllApplicationsActivity
        extends SettingsActivity
      {}
      
      public static class AndroidBeamSettingsActivity
        extends SettingsActivity
      {}
      
      public static class ApnEditorActivity
        extends SettingsActivity
      {}
      
      public static class ApnSettingsActivity
        extends SettingsActivity
      {}
      
      public static class AppDrawOverlaySettingsActivity
        extends SettingsActivity
      {}
      
      public static class AppMemoryUsageActivity
        extends SettingsActivity
      {}
      
      public static class AppNotificationSettingsActivity
        extends SettingsActivity
      {}
      
      public static class AppWriteSettingsActivity
        extends SettingsActivity
      {}
      
      public static class AvailableVirtualKeyboardActivity
        extends SettingsActivity
      {}
      
      public static class BackgroundCheckSummaryActivity
        extends SettingsActivity
      {}
      
      public static class BatterySaverSettingsActivity
        extends SettingsActivity
      {}
      
      public static class BluetoothSettingsActivity
        extends SettingsActivity
      {}
      
      public static class CaptioningSettingsActivity
        extends SettingsActivity
      {}
      
      public static class ChooseAccountActivity
        extends SettingsActivity
      {}
      
      public static class ConfigureNotificationSettingsActivity
        extends SettingsActivity
      {}
      
      public static class CryptKeeperSettingsActivity
        extends SettingsActivity
      {}
      
      public static class DataUsageSummaryActivity
        extends SettingsActivity
      {}
      
      public static class DateTimeSettingsActivity
        extends SettingsActivity
      {}
      
      public static class DevelopmentSettingsActivity
        extends SettingsActivity
      {}
      
      public static class DeviceAdminSettingsActivity
        extends SettingsActivity
      {}
      
      public static class DeviceInfoSettingsActivity
        extends SettingsActivity
      {}
      
      public static class DeviceSettings
        extends SettingsActivity
      {}
      
      public static class DisplaySettingsActivity
        extends SettingsActivity
      {}
      
      public static class DomainsURLsAppListActivity
        extends SettingsActivity
      {}
      
      public static class DreamSettingsActivity
        extends SettingsActivity
      {}
      
      public static class FingerprintEnrollSuggestionActivity
        extends FingerprintEnrollIntroduction
      {}
      
      public static class FingerprintSuggestionActivity
        extends FingerprintSettings
      {}
      
      public static class HighPowerApplicationsActivity
        extends SettingsActivity
      {}
      
      public static class HomeSettingsActivity
        extends SettingsActivity
      {}
      
      public static class IccLockSettingsActivity
        extends SettingsActivity
      {}
      
      public static class ImeiInformationActivity
        extends SettingsActivity
      {}
      
      public static class InputMethodAndLanguageSettingsActivity
        extends SettingsActivity
      {}
      
      public static class KeyboardLayoutPickerActivity
        extends SettingsActivity
      {}
      
      public static class LocalePickerActivity
        extends SettingsActivity
      {}
      
      public static class LocationSettingsActivity
        extends SettingsActivity
      {}
      
      public static class ManageApplicationsActivity
        extends SettingsActivity
      {}
      
      public static class ManageAssistActivity
        extends SettingsActivity
      {}
      
      public static class MemorySettingsActivity
        extends SettingsActivity
      {}
      
      public static class NotificationAccessSettingsActivity
        extends SettingsActivity
      {}
      
      public static class NotificationAppListActivity
        extends SettingsActivity
      {}
      
      public static class NotificationStationActivity
        extends SettingsActivity
      {}
      
      public static class NotificationStatusbarSettingsActivity
        extends SettingsActivity
      {}
      
      public static class OtherSoundSettingsActivity
        extends SettingsActivity
      {}
      
      public static class OverlaySettingsActivity
        extends SettingsActivity
      {}
      
      public static class PaymentSettingsActivity
        extends SettingsActivity
      {}
      
      public static class PersonalSettings
        extends SettingsActivity
      {}
      
      public static class PhysicalKeyboardActivity
        extends SettingsActivity
      {}
      
      public static class PowerUsageSummaryActivity
        extends SettingsActivity
      {}
      
      public static class PrintJobSettingsActivity
        extends SettingsActivity
      {}
      
      public static class PrintSettingsActivity
        extends SettingsActivity
      {}
      
      public static class PrivacySettingsActivity
        extends SettingsActivity
      {}
      
      public static class PrivateVolumeForgetActivity
        extends SettingsActivity
      {}
      
      public static class PrivateVolumeSettingsActivity
        extends SettingsActivity
      {}
      
      public static class PublicVolumeSettingsActivity
        extends SettingsActivity
      {}
      
      public static class RunningServicesActivity
        extends SettingsActivity
      {}
      
      public static class SavedAccessPointsSettingsActivity
        extends SettingsActivity
      {}
      
      public static class ScreenLockSuggestionActivity
        extends ChooseLockGeneric
      {}
      
      public static class SecuritySettingsActivity
        extends SettingsActivity
      {}
      
      public static class SimSettingsActivity
        extends SettingsActivity
      {}
      
      public static class SimStatusActivity
        extends SettingsActivity
      {}
      
      public static class SoundSettingsActivity
        extends SettingsActivity
      {}
      
      public static class SpellCheckersSettingsActivity
        extends SettingsActivity
      {}
      
      public static class StatusActivity
        extends SettingsActivity
      {}
      
      public static class StorageSettingsActivity
        extends SettingsActivity
      {}
      
      public static class StorageUseActivity
        extends SettingsActivity
      {}
      
      public static class SystemSettings
        extends SettingsActivity
      {}
      
      public static class TestingSettingsActivity
        extends SettingsActivity
      {}
      
      public static class TetherSettingsActivity
        extends SettingsActivity
      {}
      
      public static class TextToSpeechSettingsActivity
        extends SettingsActivity
      {}
      
      public static class TopLevelSettings
        extends SettingsActivity
      {}
      
      public static class TrustedCredentialsSettingsActivity
        extends SettingsActivity
      {}
      
      public static class UsageAccessSettingsActivity
        extends SettingsActivity
      {}
      
      public static class UserDictionarySettingsActivity
        extends SettingsActivity
      {}
      
      public static class UserSettingsActivity
        extends SettingsActivity
      {}
      
      public static class VpnSettingsActivity
        extends SettingsActivity
      {}
      
      public static class VrListenersSettingsActivity
        extends SettingsActivity
      {}
      
      public static class WallpaperSettingsActivity
        extends SettingsActivity
      {}
      
      public static class WallpaperSuggestionActivity
        extends SettingsActivity
      {}
      
      public static class WifiAPITestActivity
        extends SettingsActivity
      {}
      
      public static class WifiCallingSettingsActivity
        extends SettingsActivity
      {}
      
      public static class WifiCallingSuggestionActivity
        extends SettingsActivity
      {}
      
      public static class WifiDisplaySettingsActivity
        extends SettingsActivity
      {}
      
      public static class WifiInfoActivity
        extends SettingsActivity
      {}
      
      public static class WifiP2pSettingsActivity
        extends SettingsActivity
      {}
      
      public static class WifiSettingsActivity
        extends SettingsActivity
      {}
      
      public static class WirelessSettings
        extends SettingsActivity
      {}
      
      public static class WirelessSettingsActivity
        extends SettingsActivity
      {}
      
      public static class WriteSettingsActivity
        extends SettingsActivity
      {}
      
      public static class ZenAccessSettingsActivity
        extends SettingsActivity
      {}
      
      public static class ZenModeAutomationSettingsActivity
        extends SettingsActivity
      {}
      
      public static class ZenModeAutomationSuggestionActivity
        extends SettingsActivity
      {}
      
      public static class ZenModeEventRuleSettingsActivity
        extends SettingsActivity
      {}
      
      public static class ZenModeExternalRuleSettingsActivity
        extends SettingsActivity
      {}
      
      public static class ZenModePrioritySettingsActivity
        extends SettingsActivity
      {}
      
      public static class ZenModeScheduleRuleSettingsActivity
        extends SettingsActivity
      {}
      
      public static class ZenModeSettingsActivity
        extends SettingsActivity
      {}
      
      public static class ZenModeVisualInterruptionSettingsActivity
        extends SettingsActivity
      {}
    }
    

    Settings.java定义了大量静态内部类,没有任何跟界面UI相关的内容。这时候我就很困惑了,跳转到无障碍服务设置界面的内部实现是什么样的,不过从源码上看应该是AccessibilitySettingsActivity这个类,其继承自SettingsActivity类,所以继续跟踪。

    SettingsActivity

    public class SettingsActivity extends SettingsDrawerActivity
      implements PreferenceManager.OnPreferenceTreeClickListener, PreferenceFragment.OnPreferenceStartFragmentCallback, ButtonBarHandler, FragmentManager.OnBackStackChangedListener, SearchView.OnQueryTextListener, SearchView.OnCloseListener, MenuItemCompat.OnActionExpandListener
    {
    

    SettingsDrawerActivity类最终继承自Activity,所以我们应该从onCreate()入手。

      protected void onCreate(Bundle paramBundle)
      {
        super.onCreate(paramBundle);
        System.currentTimeMillis();
        Object localObject = Settings.Secure.getUriFor("mz_current_power_mode");
        getContentResolver().registerContentObserver((Uri)localObject, false, this.mPowerSaveObserver, -1);
    // Should happen before any call to getIntent()
        getMetaData();
        localObject = getIntent();
    

    这里有个获取MetaData的方法,我们看一下这个方法的具体实现,同时我们从注释还可以看到这个方法需要在调用getIntent()之前进行调用。

      private void getMetaData()
      {
        try
        {
          ActivityInfo localActivityInfo = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
          if (localActivityInfo != null)
          {
            if (localActivityInfo.metaData == null) {
              return;
            }
            this.mFragmentClass = localActivityInfo.metaData.getString("com.android.settings.FRAGMENT_CLASS");
            return;
          }
        }
        catch (PackageManager.NameNotFoundException localNameNotFoundException)
        {
          Log.d("Settings", "Cannot get Metadata for: " + getComponentName().toString());
          return;
        }
      }
    

    这个函数的作用就是从Activity标签中获取meta-data中key为com.android.settings.FRAGMENT_CLASS的值,并将其赋值给mFragmentClass 。所以我们应该再去AndroidManifest.xml查看AccessibilitySettingsActivity相关内容,具体如下:

            <activity android:configChanges="keyboardHidden|orientation|screenSize" android:icon="@drawable/mz_function_list_ic_accessibility" android:label="@string/accessibility_settings" android:name="com.android.settings.Settings$AccessibilitySettingsActivity" android:taskAffinity="">
                <intent-filter android:priority="1">
                    <action android:name="android.settings.ACCESSIBILITY_SETTINGS"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                </intent-filter>
                <intent-filter>
                    <action android:name="android.intent.action.VIEW"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                    <category android:name="android.intent.category.BROWSABLE"/>
                    <data android:host="com.android.settings" android:path="/accessibility_settings" android:scheme="flyme_3dtouch"/>
                </intent-filter>
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                    <category android:name="android.intent.category.VOICE_LAUNCH"/>
                    <category android:name="com.android.settings.SHORTCUT"/>
                </intent-filter>
                <intent-filter android:priority="3">
                    <action android:name="com.android.settings.action.SETTINGS"/>
                </intent-filter>
                <meta-data android:name="com.android.settings.category" android:value="com.android.settings.category.system"/>
                <meta-data android:name="com.android.settings.FRAGMENT_CLASS" android:value="com.meizu.settings.accessibility.FlymeAccessibilitySettings"/>
                <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" android:value="true"/>
                <meta-data android:name="usagestats.event" android:value="accessibility_settings-click"/>
            </activity>
    

    从上面可以看出mFragmentClass = “com.meizu.settings.accessibility.FlymeAccessibilitySettings”。
    找到了Fragment,就要看看它是怎么加载Fragment的,继续看onCreate函数,接下来就跟踪到了getIntent()方法:

      public Intent getIntent()
      {
        Intent localIntent1 = super.getIntent();
        Object localObject = getStartingFragmentClass(localIntent1);
        if (localObject != null)
        {
          Intent localIntent2 = new Intent(localIntent1);
          localIntent2.putExtra(":settings:show_fragment", (String)localObject);
          localObject = localIntent1.getExtras();
          if (localObject != null) {}
          for (localObject = new Bundle((Bundle)localObject);; localObject = new Bundle())
          {
            ((Bundle)localObject).putParcelable("intent", localIntent1);
            localIntent2.putExtra(":settings:show_fragment_args", (Bundle)localObject);
            return localIntent2;
          }
        }
        return localIntent1;
      }
    
      private String getStartingFragmentClass(Intent paramIntent)
      {
        if (this.mFragmentClass != null) {
          return this.mFragmentClass;
        }
        String str = paramIntent.getComponent().getClassName();
        if (str.equals(getClass().getName())) {
          return null;
        }
        if ((!"com.android.settings.ManageApplications".equals(str)) && (!"com.android.settings.RunningServices".equals(str)))
        {
          paramIntent = str;
          if (!"com.android.settings.applications.StorageUse".equals(str)) {}
        }
        else
        {
          paramIntent = ManageApplications.class.getName();
        }
        return paramIntent;
      }
    

    从源码可以看出getIntent()就是返回了一个Intent,并传了一个参数(key为:settings:show_fragment,value为mFragmentClass指定的Fragment类名)。
    分析了getIntent,继续往下看onCreate函数,看这个intent是如何使用的。

          if (!this.mIsShowingDashboard)
          {
            this.mDisplaySearch = false;
            if (this.mIsShortcut) {
              this.mDisplayHomeAsUpEnabled = bool;
            }
            for (;;)
            {
              setTitleFromIntent((Intent)localObject);
              switchToFragment(str1, ((Intent)localObject).getBundleExtra(":settings:show_fragment_args"), true, false, this.mInitialTitleResId, this.mInitialTitle, false);
              break;
              if (bool)
              {
                this.mDisplayHomeAsUpEnabled = true;
                this.mDisplaySearch = false;
              }
              else
              {
                this.mDisplayHomeAsUpEnabled = true;
              }
            }
          }
    

    从上面源码大概能看出关键部分应该是switchToFragment()函数。我们再看一下switchToFragment的实现:

      private Fragment switchToFragment(String paramString, Bundle paramBundle, boolean paramBoolean1, boolean paramBoolean2, int paramInt, CharSequence paramCharSequence, boolean paramBoolean3)
      {
        if (FlymeDashboardSummary.isConnectivitySettingsFragment(paramString))
        {
          FlymeDashboardSummary.startWithFragment(this, paramString, paramBundle, null, 0, this.mInitialTitleResId, this.mInitialTitle);
          finish();
          return null;
        }
        if ((!paramBoolean1) || (isValidFragment(paramString)))
        {
          paramString = Fragment.instantiate(this, paramString, paramBundle);
          paramBundle = getFragmentManager().beginTransaction();
          paramBundle.replace(this.mMainContentId, paramString);
          if (paramBoolean3) {
            TransitionManager.beginDelayedTransition(this.mContent);
          }
          if (paramBoolean2) {
            paramBundle.addToBackStack(":settings:prefs");
          }
          if (paramInt <= 0) {
            break label145;
          }
          paramBundle.setBreadCrumbTitle(paramInt);
        }
        for (;;)
        {
          paramBundle.commitAllowingStateLoss();
          getFragmentManager().executePendingTransactions();
          return paramString;
          throw new IllegalArgumentException("Invalid fragment for this activity: " + paramString);
          label145:
          if (paramCharSequence != null) {
            paramBundle.setBreadCrumbTitle(paramCharSequence);
          }
        }
      }
    

    从上面可以看出先通过指定的mFragment实例化fragment,然后通过FragmentTransaction的replace方法加载fragment。
    通过上述分析,我们知道了Settings.apk如何通过隐式的Intent调转到对应的Activity布局。
    当然到这一步还是不能帮我解决问题,还是没有解决魅族手机无法通过常见的方法跳到系统设置的无障碍服务的问题。

    FlymeAccessibilitySettings类

    从上面的分析我们已经能够知道魅族手机设置-->辅助功能对应的Fragment是FlymeAccessibilitySettings这个类,源码如下:

    public class FlymeAccessibilitySettings  extends SettingsPreferenceFragment 
    implements DialogInterface.OnClickListener, Preference.OnPreferenceChangeListener, Indexable
    {
    ....
    }
    public class SettingsPreferenceFragment extends PreferenceFragment
      implements DialogCreatable
    {
    ...
    }
    

    可以看出FlymeAccessibilitySettings是继承自PreferenceFragment类(关于这个类的用法待下一篇笔记补上),它一个最重要的方法是调用addPreferencesFromResource()参数为xml资源id,来加载静态xml资源文件 (在res文件夹下新建xml文件夹,再在xml文件中新建对应的xml资源),完成Preference界面的构建。所以我们可以依次找到FlymeAccessibilitySettings对应的xml资源文件为mz_accessibility_settings.xml,内容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <android.preference.PreferenceScreen android:title="@string/accessibility_settings"
      xmlns:android="http://schemas.android.com/apk/prv/res/android">
        <android.preference.PreferenceCategory android:title="@string/interactive" android:key="interactive" />
        <android.preference.Preference android:title="@string/multi_task_title" android:key="multi_task" android:widgetLayout="@167968832" android:fragment="com.meizu.settings.accessibility.FlymeMultiTaskFragment" />
        <android.preference.Preference android:title="@string/quick_wakeup_title" android:key="quick_wakeup" android:summary="@string/quick_wakeup_tips" android:widgetLayout="@167968832" android:fragment="com.meizu.settings.accessibility.FlymeQuickWakeupFragment" />
        <android.preference.Preference android:title="@string/smart_voice_wakeup" android:key="smart_voice_wakeup" android:summary="@string/smart_voice_wakeup_tips" android:widgetLayout="@167968832" />
        <android.preference.Preference android:title="@string/smart_touch_title" android:key="smart_touch" android:summary="@string/smart_touch_tips" android:widgetLayout="@167968832" android:fragment="com.meizu.settings.accessibility.FlymeSmartTouchFragment" />
        <android.preference.Preference android:title="@string/force_touch_title" android:key="force_touch" android:widgetLayout="@167968832" android:fragment="com.meizu.settings.accessibility.ForceTouchSettingsFragment" />
        <android.preference.PreferenceCategory android:title="@string/header_category_lab" android:key="interactive" />
        <android.preference.Preference android:title="@string/safe_family_title" android:key="safe_family" android:widgetLayout="@167968832" />
        <android.preference.Preference android:title="@string/children_mode_title" android:key="children_mode" android:widgetLayout="@167968832" />
        <android.preference.Preference android:title="@string/app_clone_title" android:key="app_clone" android:widgetLayout="@167968832" android:fragment="com.meizu.settings.appclone.AppCloneSettings" />
        <android.preference.Preference android:title="@string/game_mode_title" android:key="game_mode" android:widgetLayout="@167968832" android:fragment="com.meizu.settings.accessibility.GameModeSettings" />
        <android.preference.Preference android:title="@string/red_envelope_title" android:key="red_envelope_assistant" android:widgetLayout="@167968832" android:fragment="com.meizu.settings.notificationstatusbar.FlymeRedEnvelopeAssistantSettings" />
        <android.preference.Preference android:title="@string/flashlamp_effects_title" android:key="flashlamp_effects" android:widgetLayout="@167968832" android:fragment="com.meizu.settings.accessibility.FlymeFlashLampEffectsSettings" />
        <android.preference.Preference android:title="@string/classic_mode" android:key="classic_mode" android:widgetLayout="@167968832" android:fragment="com.meizu.settings.accessibility.FlymeClassicModeFragment" />
        <android.preference.PreferenceCategory android:title="@string/accessiblity_category_system" android:key="accessiblity_category_system" />
        <ListPreference android:persistent="false" android:entries="@array/home_key_behavior_double_click_entries" android:title="@string/home_key_behavior_double_click" android:key="home_double_click" android:entryValues="@array/home_key_behavior_double_click_values" />
        <ListPreference android:persistent="false" android:entries="@array/home_key_behavior_entries" android:title="@string/home_key_behavior" android:key="home_long_press" android:entryValues="@array/home_key_behavior_values" />
        <ListPreference android:persistent="false" android:entries="@array/keyboard_back_behavior_entries" android:title="@string/keyboard_back_behavior" android:key="keyboard_back_behavior" android:entryValues="@array/keyboard_back_behavior_values" />
        <com.meizu.common.preference.SwitchPreference android:persistent="false" android:title="@string/headset_middlekey_wakeup" android:key="headset_middlekey_wakeup" android:summary="@string/headset_middlekey_wakeup_summay" />
        <com.meizu.common.preference.SwitchPreference android:title="@string/light_feedback_enable_title" android:key="light_feedback" android:defaultValue="true" />
        <com.meizu.common.preference.SwitchPreference android:title="@string/keyguard_palm_rejection_title" android:key="palm_rejection" android:summary="@string/keyguard_palm_rejection_summary" android:defaultValue="true" />
        <com.meizu.common.preference.SwitchPreference android:title="@string/hall_switch_title" android:key="use_cover" android:summary="@string/hall_switch_summary" android:defaultValue="true" />
        <com.meizu.common.preference.SwitchPreference android:title="@string/mcharge_title" android:key="fast_charge" android:defaultValue="true" />
        <android.preference.Preference android:title="@string/search_settings_title" android:key="search_settings" android:widgetLayout="@167968832" />
        <android.preference.Preference android:title="@string/scheduled_power_onandoff_title" android:key="scheduled_power" android:widgetLayout="@167968832" android:fragment="com.meizu.settings.scheduledpower.ScheduledPowerFragment" />
        <android.preference.Preference android:title="@string/drive_mode_title" android:key="drive_mode" android:widgetLayout="@167968832" android:fragment="com.meizu.settings.drivemode.MzDriveModeFragment" />
        <android.preference.PreferenceScreen android:title="@string/accessible" android:key="accessible_settings" android:fragment="com.android.settings.accessibility.AccessibilitySettings" />
        <com.meizu.settings.calibration.ProximityCalibraton android:title="@string/sensor_adjust_title" android:key="sensor_adjust_proximity" />
        <com.meizu.settings.calibration.GsensorCalibration android:title="@string/gsensor_calibrate_text" android:key="sensor_adjust_gsensor" />
        <android.preference.Preference android:title="@string/development_settings_title" android:key="development_settings" android:widgetLayout="@167968832" android:fragment="com.android.settings.DevelopmentSettings" />
        <com.meizu.common.preference.SwitchPreference android:title="@string/data_collection_title" android:key="data_collection" />
    </android.preference.PreferenceScreen>
    

    对照着手机界面,我们可以确认这个xml文件就是FlymeAccessibilitySettings类的静态资源文件,从中我们可以找到魅族手机无障碍服务对应的Fragment:

        <android.preference.PreferenceScreen android:title="@string/accessible" android:key="accessible_settings" android:fragment="com.android.settings.accessibility.AccessibilitySettings" />
    

    在PreferenceFragment中点击列表项的点击监听方法为onPreferenceTreeClick();在FlymeAccessibilitySettings类中的源码如下:

     public boolean onPreferenceTreeClick(PreferenceScreen paramPreferenceScreen, Preference paramPreference)
     {
       int k = 0;
       int m = 0;
       int i = 0;
       int j = 1;
       this.mUsageStatsProxy.reportData("AccessibilitySettings", paramPreference.getKey(), paramPreference);
       if (paramPreference == this.mHomeLightSwitchPreference)
       {
         paramPreferenceScreen = this.mContentResolver;
         if (this.mHomeLightSwitchPreference.isChecked()) {
           i = 1;
         }
         Settings.System.putInt(paramPreferenceScreen, "light_feedback_enabled", i);
         return true;
       }
       if (paramPreference == this.mDataCollectionSwitch)
       {
         if (this.mDataCollectionSwitch.isChecked())
         {
           warnDataCollection();
           return true;
         }
         Settings.System.putInt(this.mContentResolver, "meizu_data_collection", 0);
         return true;
       }
       if (paramPreference == this.mSearchPreference)
       {
         paramPreferenceScreen = new Intent();
         paramPreferenceScreen.setAction("com.meizu.net.search.setting");
         paramPreferenceScreen.addFlags(335544320);
         try
         {
           startActivity(paramPreferenceScreen);
           return true;
         }
         catch (ActivityNotFoundException paramPreferenceScreen)
         {
           Log.e("AccessibilitySettings", "ActivityNotFoundException for search preference");
           return true;
         }
       }
       if (paramPreference == this.mHeadsetMiddleKeyWakeupPreference)
       {
         paramPreferenceScreen = this.mContentResolver;
         i = k;
         if (this.mHeadsetMiddleKeyWakeupPreference.isChecked()) {
           i = 1;
         }
         Settings.System.putInt(paramPreferenceScreen, "headset_middle_key_wakeup", i);
         return true;
       }
       if (paramPreference == this.mSmartVoiceWakeupPreference) {
         try
         {
           paramPreferenceScreen = new Intent("com.mediatek.voicecommand.VOICE_CONTROL_SETTINGS");
           paramPreferenceScreen.addFlags(335544320);
           startActivity(paramPreferenceScreen);
           return true;
         }
         catch (ActivityNotFoundException paramPreferenceScreen)
         {
           Log.e("AccessibilitySettings", "ActivityNotFoundException for MTK voice wakeup preference");
           startFragment(this, "com.meizu.settings.accessibility.FlymeSmartVoiceWakeupFragment", 2131627644, -1, null);
           return true;
         }
       }
       if (this.mFlymeInnovation.onPreferenceTreeClick(paramPreferenceScreen, paramPreference)) {
         return true;
       }
       if (paramPreference == this.mPalmRejection)
       {
         paramPreferenceScreen = this.mContentResolver;
         i = m;
         if (this.mPalmRejection.isChecked()) {
           i = 1;
         }
         Settings.System.putInt(paramPreferenceScreen, "keyguard_palm_rejection", i);
         return true;
       }
       if (paramPreference == this.mFastCharge) {
         if (!this.mFastCharge.isChecked())
         {
           this.mChargeDialog = new AlertDialog.Builder(this.mContext, 5).setMessage(2131628228).setPositiveButton(17039379, this).setNegativeButton(17039369, this).show();
           this.mChargeDialog.setOnDismissListener(new DialogInterface.OnDismissListener()
           {
             public void onDismiss(DialogInterface paramAnonymousDialogInterface)
             {
               boolean bool = true;
               paramAnonymousDialogInterface = FlymeAccessibilitySettings.-get4(FlymeAccessibilitySettings.this);
               if (Settings.Global.getInt(FlymeAccessibilitySettings.-get0(FlymeAccessibilitySettings.this), "mz_fast_charge", 1) == 1) {}
               for (;;)
               {
                 paramAnonymousDialogInterface.setChecked(bool);
                 return;
                 bool = false;
               }
             }
           });
         }
       }
       for (;;)
       {
         return super.onPreferenceTreeClick(paramPreferenceScreen, paramPreference);
         Settings.Global.putInt(this.mContentResolver, "mz_fast_charge", 1);
         continue;
         if (paramPreference == this.mHallSwitch)
         {
           boolean bool = this.mHallSwitch.isChecked();
           ContentResolver localContentResolver = this.mContentResolver;
           if (bool) {}
           for (i = j;; i = 0)
           {
             Settings.System.putInt(localContentResolver, "hall_switch", i);
             this.mUsageStatsProxy.reportData(FlymeAccessibilitySettings.class.getSimpleName(), paramPreference.getKey(), paramPreference);
             break;
           }
         }
         if (paramPreference == this.mSafeFamilyPreference) {
           startActivity(getBreakingScamIntent());
         }
       }
     }
    

    从上面我们可以分析出对辅助功能界面各个item的处理,不过最重要的对无障碍的处理是super.onPreferenceTreeClick(paramPreferenceScreen, paramPreference),继续跟踪下去,FlymeAccessibilitySettings的父类为SettingsPreferenceFragment,源码如下:

      public boolean onPreferenceTreeClick(PreferenceScreen paramPreferenceScreen, Preference paramPreference)
      {
        if (paramPreference.getFragment() != null) {
          return ((SettingsActivity)getActivity()).onPreferenceStartFragment(this, paramPreference);
        }
        return super.onPreferenceTreeClick(paramPreferenceScreen, paramPreference);
      }
    

    因为无障碍服务对应的是另一个Fragment,所以进入if块,调用onPreferenceStartFragment(),源码如下:

      public boolean onPreferenceStartFragment(SettingsPreferenceFragment paramSettingsPreferenceFragment, android.preference.Preference paramPreference)
      {
        paramSettingsPreferenceFragment = paramPreference.getTitle();
        if (paramPreference.getFragment().equals(WallpaperTypeSettings.class.getName())) {
          paramSettingsPreferenceFragment = getString(2131625303);
        }
        startPreferencePanel(paramPreference.getFragment(), paramPreference.getExtras(), -1, paramSettingsPreferenceFragment, null, 0);
        return true;
      }
    
      public void startPreferencePanel(String paramString, Bundle paramBundle, int paramInt1, CharSequence paramCharSequence, Fragment paramFragment, int paramInt2)
      {
        String str = null;
        if (paramInt1 < 0) {
          if (paramCharSequence == null) {
            break label39;
          }
        }
        label39:
        for (str = paramCharSequence.toString();; str = "")
        {
          Utils.startWithFragment(this, paramString, paramBundle, paramFragment, paramInt2, paramInt1, str, this.mIsShortcut);
          return;
        }
      }
    

    到这一步可以发现最终调用的是Utils.startWithFragment(),我本以为见到曙光了...不过 too young too native
    继续往下看:

      public static void startWithFragment(Context paramContext, String paramString, Bundle paramBundle, Fragment paramFragment, int paramInt1, int paramInt2, CharSequence paramCharSequence, boolean paramBoolean)
      {
        paramString = onBuildStartFragmentIntent(paramContext, paramString, paramBundle, null, paramInt2, paramCharSequence, paramBoolean);
        if (paramFragment == null)
        {
          paramContext.startActivity(paramString);
          return;
        }
        paramFragment.startActivityForResult(paramString, paramInt1);
      }
    
      public static Intent onBuildStartFragmentIntent(Context paramContext, String paramString1, Bundle paramBundle, String paramString2, int paramInt, CharSequence paramCharSequence, boolean paramBoolean)
      {
        Intent localIntent = new Intent("android.intent.action.MAIN");
        localIntent.setClass(paramContext, SubSettings.class);
        localIntent.putExtra(":settings:show_fragment", paramString1);
        localIntent.putExtra(":settings:show_fragment_args", paramBundle);
        localIntent.putExtra(":settings:show_fragment_title_res_package_name", paramString2);
        localIntent.putExtra(":settings:show_fragment_title_resid", paramInt);
        localIntent.putExtra(":settings:show_fragment_title", paramCharSequence);
        localIntent.putExtra(":settings:show_fragment_as_shortcut", paramBoolean);
        return localIntent;
      }
    

    不难发现从调用无障碍服务的方式是startActivityForResult(),在这个之前会先调用onBuildStartFragmentInten()构造一个intent。首先我们看到方法内部所调用的Activity为SubSettings类,源码如下:

    public class SubSettings extends SettingsActivity
    {
      protected boolean isValidFragment(String paramString)
      {
        Log.d("SubSettings", "Launching fragment " + paramString);
        return true;
      }
      
      public boolean onNavigateUp()
      {
        finish();
        return true;
      }
    }
    

    SubSettings继承自SettingsActivity,我们在之前的分析已经能得出SettingsActivity加载Fragment的方式是从AndroidManifest.xml的Activity标签中获取meta-data中key为com.android.settings.FRAGMENT_CLASS的值,我们看下SubSettings的声明:

            <activity android:configChanges="keyboardHidden|orientation|screenSize" android:exported="true" android:name="com.android.settings.SubSettings" android:parentActivityName="com.android.settings.Settings" android:permission="com.meizu.permission.SEARCH_SETTINGS" android:screenOrientation="portrait" android:taskAffinity="com.android.settings">
                <intent-filter>
                    <action android:name="android.intent.action.SEARCH"/>
                </intent-filter>
                <meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/>
            </activity>
    

    并没有我们所需要的值,但在getIntent中我们可以发现intent值来自super.getIntent();,最后通过调用switchToFragment()加载无障碍服务对应的Fragment。所以我们可以尝试着构造一样的intent在我们自己的应用中调用魅族手机的无障碍服务
    代码如下:

            intent.setAction("android.intent.action.SEARCH");
            intent.setComponent(new ComponentName("com.android.settings", "com.android.settings.SubSettings"));
            intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, "com.android.settings.accessibility.AccessibilitySettings");
            startActivity(intent);
    

    因为跳转SubSettings这个Activity需要声明一个permission,所以我们必须在我们应用加上这个权限声明,但是这会引来另一个问题:Failure [INSTALL_FAILED_DUPLICATE_PERMISSION,这个错误的意思是正要安装的APP的自定义权限与手机上已有APP的自定义权限名字相同,但两个APP具有不同的签名信息导致安装失败。

    相关文章

      网友评论

        本文标题:魅族Android7.0 Settings源码分析

        本文链接:https://www.haomeiwen.com/subject/fqxijftx.html