今天的主角:com.android.settings.wifi.WifiSettings基类;
一、WifiSettings.java
/**
* Two types of UI are provided here.
* 有两种UI界面,在这里,第一种是手机需要链接wifi激活的界面,第二种是激活的正常显示界面
* The first is for "usual Settings", appearing as any other Setup fragment.
*
* The second is for Setup Wizard, with a simplified interface that hides the action bar
* and menus.
*/
public class WifiSettings extends RestrictedSettingsFragment
implements DialogInterface.OnClickListener, Indexable {
private static final String TAG = "WifiSettings";
1、按照惯例,分析类中有哪些继承和实现
2、首先继承一个RestrictedSettingsFragment类,同时实现了 DialogInterface.OnClickListener接口和Indexable接口;
3、针对RestrictedSettingsFragment的作用
4、WifiSettings的结构类型,我们先暂时分析最顶层上的fragment吧;
二、PreferenceFragment类的分析
public abstract class PreferenceFragment extends Fragment implements
PreferenceManager.OnPreferenceTreeClickListener {
private static final String PREFERENCES_TAG = "android:preferences";
private PreferenceManager mPreferenceManager;
private ListView mList;
private boolean mHavePrefs;
private boolean mInitDone;
private int mLayoutResId = com.android.internal.R.layout.preference_list_fragment;
1、从上可以看出集成Fragment,实现了接口PreferenceManager.OnPreferenceTreeClickListener;
/**
* Interface definition for a callback to be invoked when a
* {@link Preference} in the hierarchy rooted at this {@link PreferenceScreen} is
* clicked.
*
* @hide
*/
public interface OnPreferenceTreeClickListener {
/**
* Called when a preference in the tree rooted at this
* {@link PreferenceScreen} has been clicked.
*
* @param preferenceScreen The {@link PreferenceScreen} that the
* preference is located in.
* @param preference The preference that was clicked.
* @return Whether the click was handled.
*/
boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference);
}
2、接口实现中,有一个onPreferenceTreeClick方法;
三、重点分析基类SettingsPreferenceFragment
/**
* Base class for Settings fragments, with some helper functions and dialog management.
*/
public class SettingsPreferenceFragment extends PreferenceFragment implements DialogCreatable {
private static final String TAG = "SettingsPreferenceFragment";
private static final int MENU_HELP = Menu.FIRST + 100;//菜单帮助id
private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600;//延迟高亮
private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";//保存高亮
private SettingsDialogFragment mDialogFragment;//对话框形式的Fragment
private String mHelpUrl;//帮助url
// Cache the content resolver for async callbacks
private ContentResolver mContentResolver;
private String mPreferenceKey;
private boolean mPreferenceHighlighted = false;//是否高亮
private Drawable mHighlightDrawable;//高亮的drawable
private ListAdapter mCurrentRootAdapter;//当前根视图的adapter
private boolean mIsDataSetObserverRegistered = false;
//数据集合观察者
private DataSetObserver mDataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
highlightPreferenceIfNeeded();
}
@Override
public void onInvalidated() {
highlightPreferenceIfNeeded();
}
};
1、开始定义了一些基本的数据信息;
private ViewGroup mPinnedHeaderFrameLayout;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
if (icicle != null) {//获取是否高亮的key值
mPreferenceHighlighted = icicle.getBoolean(SAVE_HIGHLIGHTED_KEY);
}
// Prepare help url and enable menu if necessary
int helpResource = getHelpResource();
if (helpResource != 0) {//获取帮助菜单的url和资源id
mHelpUrl = getResources().getString(helpResource);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//初始化视图view和mPinnedHeaderFrameLayout
final View root = super.onCreateView(inflater, container, savedInstanceState);
mPinnedHeaderFrameLayout = (ViewGroup) root.findViewById(R.id.pinned_header);
return root;
}
//设置视图,也就是加载视图pinnedHeader
public void setPinnedHeaderView(View pinnedHeader) {
mPinnedHeaderFrameLayout.addView(pinnedHeader);
mPinnedHeaderFrameLayout.setVisibility(View.VISIBLE);
}
//清除视图
public void clearPinnedHeaderView() {
mPinnedHeaderFrameLayout.removeAllViews();
mPinnedHeaderFrameLayout.setVisibility(View.GONE);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//保存是否高亮的变量
outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted);
}
2、获取一些初始化的数据;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (!TextUtils.isEmpty(mHelpUrl)) {//显示帮助菜单
setHasOptionsMenu(true);
}
}
@Override
public void onResume() {
super.onResume();
final Bundle args = getArguments();
if (args != null) {//获取mPreferenceKey,从字段EXTRA_FRAGMENT_ARG_KEY中
mPreferenceKey = args.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY);
highlightPreferenceIfNeeded();
}
}
@Override
protected void onBindPreferences() {
registerObserverIfNeeded();//注册本地数据集合监听器
}
@Override
protected void onUnbindPreferences() {
unregisterObserverIfNeeded();
}
@Override
public void onStop() {
super.onStop();
unregisterObserverIfNeeded();
}
//注册观察者
public void registerObserverIfNeeded() {
if (!mIsDataSetObserverRegistered) {
if (mCurrentRootAdapter != null) {
mCurrentRootAdapter.unregisterDataSetObserver(mDataSetObserver);
}
mCurrentRootAdapter = getPreferenceScreen().getRootAdapter();
mCurrentRootAdapter.registerDataSetObserver(mDataSetObserver);
mIsDataSetObserverRegistered = true;
}
}
//反注册观察者
public void unregisterObserverIfNeeded() {
if (mIsDataSetObserverRegistered) {
if (mCurrentRootAdapter != null) {
mCurrentRootAdapter.unregisterDataSetObserver(mDataSetObserver);
mCurrentRootAdapter = null;
}
mIsDataSetObserverRegistered = false;
}
}
//是否有必要高亮Preference
public void highlightPreferenceIfNeeded() {
if (isAdded() && !mPreferenceHighlighted &&!TextUtils.isEmpty(mPreferenceKey)) {
highlightPreference(mPreferenceKey);
}
}
//获取高亮的图片Drawable
private Drawable getHighlightDrawable() {
if (mHighlightDrawable == null) {
mHighlightDrawable = getActivity().getDrawable(R.drawable.preference_highlight);
}
return mHighlightDrawable;
}
/**
* Return a valid ListView position or -1 if none is found
* 返回一个有效的listview的position
*/
private int canUseListViewForHighLighting(String key) {
if (!hasListView()) {
return -1;
}
ListView listView = getListView();
ListAdapter adapter = listView.getAdapter();
if (adapter != null && adapter instanceof PreferenceGroupAdapter) {
return findListPositionFromKey(adapter, key);
}
return -1;
}
//通过key值查找高亮的Preference
private void highlightPreference(String key) {
final Drawable highlight = getHighlightDrawable();
//listview查找position
final int position = canUseListViewForHighLighting(key);
if (position >= 0) {
mPreferenceHighlighted = true;
final ListView listView = getListView();
final ListAdapter adapter = listView.getAdapter();
//设置高亮drawable
((PreferenceGroupAdapter) adapter).setHighlightedDrawable(highlight);
((PreferenceGroupAdapter) adapter).setHighlighted(position);
Log.w(TAG, "highlightPreference, key = " + key + ", this = " + this);
listView.post(new Runnable() {
@Override
public void run() {
Log.w(TAG, "highlightPreference, 1st runnable runs, this = " + this);
listView.setSelection(position);//设置selection
listView.postDelayed(new Runnable() {
@Override
public void run() {
Log.w(TAG, "highlightPreference, 2st runnable runs, this = " + this);
final int index = position - listView.getFirstVisiblePosition();
if (index >= 0 && index < listView.getChildCount()) {
final View v = listView.getChildAt(index);
final int centerX = v.getWidth() / 2;
final int centerY = v.getHeight() / 2;
highlight.setHotspot(centerX, centerY);
/// M: CR ALPS01838309,remove the action
//v.setPressed(true);
//v.setPressed(false);
}
}
}, DELAY_HIGHLIGHT_DURATION_MILLIS);
}
});
}
}
//在ListAdapter中通过key找到position
private int findListPositionFromKey(ListAdapter adapter, String key) {
final int count = adapter.getCount();
for (int n = 0; n < count; n++) {
final Object item = adapter.getItem(n);
if (item instanceof Preference) {
Preference preference = (Preference) item;
final String preferenceKey = preference.getKey();
if (preferenceKey != null && preferenceKey.equals(key)) {
return n;
}
}
}
return -1;
}
//通过key移除选项
protected void removePreference(String key) {
Preference pref = findPreference(key);
if (pref != null) {
getPreferenceScreen().removePreference(pref);
}
}
public static class SettingsDialogFragment extends DialogFragment {
private static final String KEY_DIALOG_ID = "key_dialog_id";
private static final String KEY_PARENT_FRAGMENT_ID = "key_parent_fragment_id";
private int mDialogId;
private Fragment mParentFragment;
private DialogInterface.OnCancelListener mOnCancelListener;
private DialogInterface.OnDismissListener mOnDismissListener;
public SettingsDialogFragment() {
/* do nothing */
}
public SettingsDialogFragment(DialogCreatable fragment, int dialogId) {
mDialogId = dialogId;
if (!(fragment instanceof Fragment)) {
throw new IllegalArgumentException("fragment argument must be an instance of "
+ Fragment.class.getName());
}
mParentFragment = (Fragment) fragment;
}
//调用返回按键
public void finish() {
getActivity().onBackPressed();
}
//启动fragment
public boolean startFragment(Fragment caller, String fragmentClass, int titleRes,
int requestCode, Bundle extras) {
final Activity activity = getActivity();
if (activity instanceof SettingsActivity) {
SettingsActivity sa = (SettingsActivity) activity;
sa.startPreferencePanel(fragmentClass, extras, titleRes, null, caller, requestCode);
return true;
} else if (activity instanceof PreferenceActivity) {
PreferenceActivity sa = (PreferenceActivity) activity;
sa.startPreferencePanel(fragmentClass, extras, titleRes, null, caller, requestCode);
return true;
} else {
Log.w(TAG,
"Parent isn't SettingsActivity nor PreferenceActivity, thus there's no way to "
+ "launch the given Fragment (name: " + fragmentClass
+ ", requestCode: " + requestCode + ")");
return false;
}
}
四、重点分析基类:RestrictedSettingsFragment
/**
* Base class for settings screens that should be pin protected when in restricted mode.
* The constructor for this class will take the restriction key that this screen should be
* locked by. If {@link RestrictionsManager.hasRestrictionsProvider()} and
* {@link UserManager.hasUserRestriction()}, then the user will have to enter the restrictions
* pin before seeing the Settings screen.
*
* If this settings screen should be pin protected whenever
* {@link RestrictionsManager.hasRestrictionsProvider()} returns true, pass in
* {@link RESTRICT_IF_OVERRIDABLE} to the constructor instead of a restrictions key.
*/
public class RestrictedSettingsFragment extends SettingsPreferenceFragment {
protected static final String RESTRICT_IF_OVERRIDABLE = "restrict_if_overridable";
// No RestrictedSettingsFragment screens should use this number in startActivityForResult.
private static final int REQUEST_PIN_CHALLENGE = 12309;
private static final String KEY_CHALLENGE_SUCCEEDED = "chsc";
private static final String KEY_CHALLENGE_REQUESTED = "chrq";
// If the restriction PIN is entered correctly.
private boolean mChallengeSucceeded;
private boolean mChallengeRequested;
private UserManager mUserManager;
private RestrictionsManager mRestrictionsManager;
private final String mRestrictionKey;
// Receiver to clear pin status when the screen is turned off.
private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!mChallengeRequested) {
mChallengeSucceeded = false;
mChallengeRequested = false;
}
}
};
1、从类名可以很明显的看出,这是一个限制的Fragment类
/**
* @param restrictionKey The restriction key to check before pin protecting
* this settings page. Pass in {@link RESTRICT_IF_OVERRIDABLE} if it should
* be protected whenever a restrictions provider is set. Pass in
* null if it should never be protected.
*/
public RestrictedSettingsFragment(String restrictionKey) {
mRestrictionKey = restrictionKey;
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mRestrictionsManager = (RestrictionsManager) getSystemService(Context.RESTRICTIONS_SERVICE);
mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
if (icicle != null) {
mChallengeSucceeded = icicle.getBoolean(KEY_CHALLENGE_SUCCEEDED, false);
mChallengeRequested = icicle.getBoolean(KEY_CHALLENGE_REQUESTED, false);
}
IntentFilter offFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
offFilter.addAction(Intent.ACTION_USER_PRESENT);
getActivity().registerReceiver(mScreenOffReceiver, offFilter);
}
2、获取intent的extra数据,注册广播;
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (getActivity().isChangingConfigurations()) {
outState.putBoolean(KEY_CHALLENGE_REQUESTED, mChallengeRequested);
outState.putBoolean(KEY_CHALLENGE_SUCCEEDED, mChallengeSucceeded);
}
}
@Override
public void onResume() {
super.onResume();
if (shouldBeProviderProtected(mRestrictionKey)) {
ensurePin();
}
}
@Override
public void onDestroy() {
getActivity().unregisterReceiver(mScreenOffReceiver);
super.onDestroy();
}
3、保存值,反注销广播;
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_PIN_CHALLENGE) {
if (resultCode == Activity.RESULT_OK) {
mChallengeSucceeded = true;
mChallengeRequested = false;
} else {
mChallengeSucceeded = false;
}
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
private void ensurePin() {
if (!mChallengeSucceeded && !mChallengeRequested
&& mRestrictionsManager.hasRestrictionsProvider()) {
Intent intent = mRestrictionsManager.createLocalApprovalIntent();
if (intent != null) {
mChallengeRequested = true;
mChallengeSucceeded = false;
PersistableBundle request = new PersistableBundle();
request.putString(RestrictionsManager.REQUEST_KEY_MESSAGE,
getResources().getString(R.string.restr_pin_enter_admin_pin));
intent.putExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE, request);
startActivityForResult(intent, REQUEST_PIN_CHALLENGE);
}
}
}
4、保证pin
继续继续。。。