作为一名软件开发工程师,曾经对于如何确认当前activity的详细信息非常想知道,后来学会了一个命令:
adb shell dumpsys activity | grep -i foc
可以方便的查看当前activity的详细信息。
但是,凡事最怕有例外
此命令一向所向披靡,帮助我解决了许多问题。但是在settings应用中,我发现了一个非常可怕的现象。在许多settings界面中,我发现此命令都是输出说当前界面的activity信息是com.android.settings/.SubSettings
,命令如下:
adb shell dumpsys activity | grep -i foc
* ContentProviderRecord{41b0d010 u0 com.google.android.gms/.ads.adinfo.AdvertisingInfoContentProvider}
mFocusedActivity: ActivityRecord{41b60318 u0 com.android.settings/.SubSettings t6}
也就是说settings应用中,许多settings界面都是说当前界面的activity信息为:com.android.settings/.SubSettings
why?
然后有一个订单项目,说要从一个任意的地方要跳转了settings应用的其中一个界面Dual SIM setting。
非常的不幸,这个Dual SIM setting界面,我们使用命令:adb shell dumpsys activity | grep -i foc,读取此界面的activity信息,正好为com.android.settings/.SubSettings。
而三方apk说要找我们要跳转接口,这……,一个activity的界面跳转,随便一个开发小菜鸟都能搞定,为什么要找我们要跳转接口呢?后来才明白,其实原因非常简单,就是他们不知道怎么跳转界面。
我感觉非常搞笑,一个界面跳转都搞不定吗?
好吧,我来试试。顺便看一下为什么settings应用下的界面为什么都只显示为com.android.settings/.SubSettings。
在settings应用的源码中裸泳了一下,再结合了一下systemui应用的下拉状态栏跳转方式(base/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java——startSettingsActivity),
特别是我发现Wi-fi界面也是显示为SubSettings,但是可以跳转,我就特别参考了Wi-fi界面来实现此跳转界面了:
先直接把实现方法列在这吧:
AndroidManifest.xml——-实现定义一下DualSimSettingsActivity:
此完全是参考WifiSettingsActivity和wifi.WifiSettings,来定义双卡设置界面,这主要是为了后面的界面跳转:
<activity android:name="Settings$DualSimSettingsActivity" android:taskAffinity="" android:label="@string/dual_sim_title">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.AIRPLANE_MODE"/>
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS" android:value="com.android.settings.DualSimSettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID" android:resource="@id/dual_sim_settings" />
</activity>
<activity-alias android:name="DualSimSettings" android:label="@string/dual_sim_title" android:exported="true" android:taskAffinity="com.android.settings" android:targetActivity="Settings$DualSimSettingsActivity" >
<meta-data android:name="com.android.settings.FRAGMENT_CLASS" android:value="com.android.settings.DualSimSettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID" android:resource="@id/dual_sim_settings" />
</activity-alias>
在Settings.java—–文件中定义DualSimSettingsActivity和其中的fragment(DualSimSettings)
apps/Settings/src/com/android/settings/Settings.java
修改记录:
import com.android.settings.wifi.AdvancedWifiSettings;
import com.android.settings.wifi.WifiEnabler;
import com.android.settings.wifi.WifiSettings;
//这个主要是引入DualSimSettings定义
+import com.android.settings.DualSimSettings;
import com.android.settings.wifi.p2p.WifiP2pSettings;
import com.android.settings.audioprofile.AudioProfileSettings;
@@ -321,6 +322,7 @@ public class Settings extends PreferenceActivity private static final String[] ENTRY_FRAGMENTS = {
WirelessSettings.class.getName(),
WifiSettings.class.getName(),
//这个主要是定义DualSimSettingsActivity中的frgments为DualSimSettings
+ DualSimSettings.class.getName(),
AdvancedWifiSettings.class.getName(),
BluetoothSettings.class.getName(),
TetherSettings.class.getName(),
@@ -523,6 +525,7 @@ public class Settings extends PreferenceActivity // Some fragments want split ActionBar; these should stay in sync with
// uiOptions for fragments also defined as activities in manifest.
if (WifiSettings.class.getName().equals(fragmentName) ||
//这个主要是定义DualSimSettingsActivity中的frgments为DualSimSettings
+ DualSimSettings.class.getName().equals(fragmentName) ||
WifiP2pSettings.class.getName().equals(fragmentName) ||
BluetoothSettings.class.getName().equals(fragmentName) ||
DreamSettings.class.getName().equals(fragmentName) ||
@@ -1135,6 +1138,7 @@ public class Settings extends PreferenceActivity //public static class SchedulePowerOnOffActivity extends Settings { /* empty */ }
public static class StorageSettingsActivity extends Settings { /* empty */ }
public static class WifiSettingsActivity extends Settings { /* empty */ }
//这个主要是定义DualSimSettingsActivity
+ public static class DualSimSettingsActivity extends Settings { /* empty */ }
public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
好了,准备工作做好了,下面就是正常的activity界面跳转了:
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName("com.android.settings",
"com.android.settings.Settings$DualSimSettingsActivity"));
startActivity(intent);
ok,打完收工。界面可以像我们平常的activity跳转了。
任何一个小菜鸟都可以直接跳转了。
看完settings应用的源码后,我们明白了为什么在settings界面下有这么多界面的activity信息为subsettings。
原因非常简单:
就是在./apps/Settings/src/com/android/settings/Settings.java文件中:
我们跳转到了SubSettings中了。
intent.setClass(this, SubSettings.class);
public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
int titleRes, int shortTitleRes) {
Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
titleRes, shortTitleRes);
// Some fragments want split ActionBar; these should stay in sync with
// uiOptions for fragments also defined as activities in manifest.
if (WifiSettings.class.getName().equals(fragmentName) ||
DualSimSettings.class.getName().equals(fragmentName) ||
WifiP2pSettings.class.getName().equals(fragmentName) ||
BluetoothSettings.class.getName().equals(fragmentName) ||
DreamSettings.class.getName().equals(fragmentName) ||
LocationSettings.class.getName().equals(fragmentName) ||
ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName) ||
PrintSettingsFragment.class.getName().equals(fragmentName) ||
PrintServiceSettingsFragment.class.getName().equals(fragmentName)) {
intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
}
intent.setClass(this, SubSettings.class);
return intent;
}
而SubSettings 就继承至Settings,(SubSettings extends Settings),Settings是继承至PreferenceActivity(Settings extends PreferenceActivity)。
也就是说Subsettings就是当前的activity。只是这个Subsettings和一般的activity不一样,他添加不同的fragment就显示不同的界面,但是他本身还是Subsettings。
我们在./apps/Settings/res/xml/settings_headers.xml可以看到settings主要界面布局:
<!-- Dual SIM Settings -->
<!-- 这是双卡设置的fragment -->
<header android:id="@+id/dual_sim_settings" android:fragment="com.android.settings.DualSimSettings" android:icon="@drawable/ic_settings_dualsim" android:title="@string/dual_sim_title">
<intent android:action="android.intent.action.MAIN"/>
</header>
<!-- Wifi -->
<!-- 这是wifi设置的fragment -->
<header android:id="@+id/wifi_settings" android:fragment="com.android.settings.wifi.WifiSettings" android:title="@string/wifi_settings_title" android:icon="@drawable/ic_settings_wireless" />
然后,我们可以仿照上面的方法,任意的一个SubSettings界面跳转。
真的,我没有骗你。