前言:
只能说对魅族手机系统很是无奈啊!!!为了分析魅族手机无法通过常见的方法跳到系统设置的无障碍服务,只好通过豌豆荚将settings.apk导出然后进行反编译,跟踪源码.......
准备工作(反编译apk以及AndroidManifest.xml文件)
- 从反编译一开始就碰上了坑,利用dex2jar-2.0无法导出classes-dex2jar.jar文件,原因暂未找到,解决方案是将classes.dex用nodepad++打开,将037,改成036,保存,再用dex2jar。
- 反编译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具有不同的签名信息导致安装失败。
网友评论