具体现象:点击右上角的修改,然后修改wifi的密码,在隐私选项和网络是否按流量计费选项与原来不同时,就会发生密码修改失败。

现在开始具体的分析:

首先找到左图页面的xml文件,和对应的控制类。

packages/apps/Settings/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java

packages/apps/Settings/res/xml/wifi_network_details_fragment2.xml

可以找到编辑按钮的创建和响应。在正常情况下走的是   showDialog(WIFI_DIALOG_ID);

@Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        Log.d("xz", "onCreateOptionsMenu: ");
        if (!mIsUiRestricted && isEditable()) {
            MenuItem item = menu.add(0, Menu.FIRST, 0, R.string.wifi_modify);
            item.setIcon(com.android.internal.R.drawable.ic_mode_edit);
            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
        }
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem menuItem) {
        Log.d("xz", "onOptionsItemSelected: menuItem.getItemId() = " + menuItem.getItemId());
        Log.d("xz", "onOptionsItemSelected: canModifyNetwork() = " + mWifiDetailPreferenceController2.canModifyNetwork());
        switch (menuItem.getItemId()) {
            case Menu.FIRST:
                if (!mWifiDetailPreferenceController2.canModifyNetwork()) {
                    EnforcedAdmin admin = RestrictedLockUtilsInternal.getDeviceOwner(getContext());
                    if (admin == null) {
                        final DevicePolicyManager dpm = (DevicePolicyManager)
                                getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
                        final UserManager um = (UserManager)
                                getContext().getSystemService(Context.USER_SERVICE);
                        final int profileOwnerUserId = Utils.getManagedProfileId(
                                um, UserHandle.myUserId());
                        if (profileOwnerUserId != UserHandle.USER_NULL) {
                            admin = new EnforcedAdmin(dpm.getProfileOwnerAsUser(profileOwnerUserId),
                                    null, UserHandle.of(profileOwnerUserId));
                        }
                    }
                    RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), admin);
                } else {
                    Log.d("xz", "WifiNetworkDetailsFragment onOptionsItemSelected: showDialog(WIFI_DIALOG_ID)");
                    showDialog(WIFI_DIALOG_ID);
                }
                return true;
            default:
                return super.onOptionsItemSelected(menuItem);
        }
    }

showDialog()方法会调用到  

packages/apps/Settings/src/com/android/settings/SettingsPreferenceFragment.java  

的showDialog() 然后创建dialog 

protected void showDialog(int dialogId) {
        Log.d("xz", "SettingsPreferenceFragment showDialog: ");
        if (mDialogFragment != null) {
            Log.e(TAG, "Old dialog fragment not null!");
        }
        mDialogFragment = SettingsDialogFragment.newInstance(this, dialogId);
        mDialogFragment.show(getChildFragmentManager(), Integer.toString(dialogId));
    }
@Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            Log.d("xz", " SettingsPreferenceFragment onCreateDialog: ");
            if (savedInstanceState != null) {
                mDialogId = savedInstanceState.getInt(KEY_DIALOG_ID, 0);
                mParentFragment = getParentFragment();
                int mParentFragmentId = savedInstanceState.getInt(KEY_PARENT_FRAGMENT_ID, -1);
                if (mParentFragment == null) {
                    mParentFragment = getFragmentManager().findFragmentById(mParentFragmentId);
                }
                if (!(mParentFragment instanceof DialogCreatable)) {
                    throw new IllegalArgumentException(
                            (mParentFragment != null
                                    ? mParentFragment.getClass().getName()
                                    : mParentFragmentId)
                                    + " must implement "
                                    + DialogCreatable.class.getName());
                }
                // This dialog fragment could be created from non-SettingsPreferenceFragment
                if (mParentFragment instanceof SettingsPreferenceFragment) {
                    // restore mDialogFragment in mParentFragment
                    ((SettingsPreferenceFragment) mParentFragment).mDialogFragment = this;
                }
            }
            return ((DialogCreatable) mParentFragment).onCreateDialog(mDialogId);
        }

可以看到最终调用了mParentFragment.onCreateDialog(mDialogId)  ,此fragmengt就是WifiNetworkDetailsFragment。

所以又调用到了WifiNetworkDetailsFragment的onCreateDialog。

@Override
    public Dialog onCreateDialog(int dialogId) {
        Log.d("xz", "WifiNetworkDetailsFragment onCreateDialog: ");
        if (getActivity() == null || mWifiDetailPreferenceController2 == null) {
            return null;
        }

        final WifiEntry wifiEntry = mNetworkDetailsTracker.getWifiEntry();
        return WifiDialog2.createModal(getActivity(), this, wifiEntry,
                WifiConfigUiBase2.MODE_MODIFY);
    }

这里又调用了WifiDialog2.createModal()

public static WifiDialog2 createModal(Context context, WifiDialog2Listener listener,
            WifiEntry wifiEntry, int mode) {
        return new WifiDialog2(context, listener, wifiEntry, mode, 0 /* style */,
                mode == WifiConfigUiBase2.MODE_VIEW /* hideSubmitButton */);
    }



@Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d("xz", "WifiDialog2 onCreate: ");
        setWindowsOverlay();

        mView = getLayoutInflater().inflate(R.layout.wifi_dialog, /* root */ null);
        setView(mView);
        mController = new WifiConfigController2(this, mView, mWifiEntry, mMode);
        super.onCreate(savedInstanceState);

        if (mHideSubmitButton) {
            mController.hideSubmitButton();
        } else {
            /* During creation, the submit button can be unavailable to determine
             * visibility. Right after creation, update button visibility */
            mController.enableSubmitIfAppropriate();
        }

        if (mWifiEntry == null) {
            mController.hideForgetButton();
        }
    }

可以看出此dialog由   WifiConfigController2   进行管理。

在WifiConfigController2  的   initWifiConfigController2   的方法中设置了  保存按钮和监听。

 private void initWifiConfigController2(WifiEntry wifiEntry, int mode) {
        Log.d("xz", "initWifiConfigController2: start");
        .............
        .............
        mConfigUi.setTitle(mWifiEntry.getTitle());

            ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);

        ...........
        if (mMode == WifiConfigUiBase2.MODE_MODIFY) {
                Log.d("xz", "initWifiConfigController2: setSubmitButton 1 ");
                mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));

这个mConfigUi  其实就是WifiDialog2类。setSubmitButton

@Override
    public void setSubmitButton(CharSequence text) {
        setButton(BUTTON_SUBMIT, text, this);
    }

此方法会调用到frameworks/base/core/java/com/android/internal/app/AlertController.java

的setButton。

 public void setButton(int whichButton, CharSequence text,
            DialogInterface.OnClickListener listener, Message msg) {

        if (msg == null && listener != null) {
            msg = mHandler.obtainMessage(whichButton, listener);
        }

        switch (whichButton) {

            case DialogInterface.BUTTON_POSITIVE:
                mButtonPositiveText = text;
                mButtonPositiveMessage = msg;
                break;

            case DialogInterface.BUTTON_NEGATIVE:
                mButtonNegativeText = text;
                mButtonNegativeMessage = msg;
                break;

            case DialogInterface.BUTTON_NEUTRAL:
                mButtonNeutralText = text;
                mButtonNeutralMessage = msg;
                break;

            default:
                throw new IllegalArgumentException("Button does not exist");
        }
    }

这里走到的是第一个。msg = mHandler.obtainMessage(whichButton, listener);用handler设置了监听

 private static final class ButtonHandler extends Handler {
        // Button clicks have Message.what as the BUTTON{1,2,3} constant
        private static final int MSG_DISMISS_DIALOG = 1;

        private WeakReference<DialogInterface> mDialog;

        public ButtonHandler(DialogInterface dialog) {
            mDialog = new WeakReference<>(dialog);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {

                case DialogInterface.BUTTON_POSITIVE:
                case DialogInterface.BUTTON_NEGATIVE:
                case DialogInterface.BUTTON_NEUTRAL:
                    ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
                    break;

                case MSG_DISMISS_DIALOG:
                    ((DialogInterface) msg.obj).dismiss();
            }
        }
    }

当点击保存按钮时就会执行((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
         这里就会调用回到wifiDialog的onClick()方法去

@Override
    public void onClick(DialogInterface dialogInterface, int id) {
        Log.e("xz", "WifiDialog2 onClick: ",new Throwable());
        if (mListener != null) {
            switch (id) {
                case BUTTON_SUBMIT:
                    mListener.onSubmit(this);
                    break;
                case BUTTON_FORGET:
                    if (WifiUtils.isNetworkLockedDown(getContext(),
                            mWifiEntry.getWifiConfiguration())) {
                        RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
                                RestrictedLockUtilsInternal.getDeviceOwner(getContext()));
                        return;
                    }
                    mListener.onForget(this);
                    break;
            }
        }
    }

执行了mListener.onSubmit(this);

这个mListener。onSubmit就是WifiNetworkDetailsFragment类里去重写的。

@Override
    public void onSubmit(WifiDialog2 dialog) {
        for (WifiDialog2.WifiDialog2Listener listener : mWifiDialogListeners) {
            listener.onSubmit(dialog);
        }
    }

这个listener.onSubmit是在此类初始化的。

 mWifiDialogListeners.add(mWifiDetailPreferenceController2);
 mWifiDialogListeners.add(privacyController2);
 mWifiDialogListeners.add(meteredPreferenceController2);
        

这3个分别是WifiDetailPreferenceController2.java、WifiDetailPreferenceController2.java、WifiDetailPreferenceController2.java。

看一些这些类的submit方法。

@Override
    public void onSubmit(WifiDialog2 dialog) {
        Log.d("xz", "WifiMeteredPreferenceController2 onSubmit: ");
        if (dialog.getController() != null && mWifiEntry.canSetMeteredChoice()) {
            final WifiConfiguration newConfig = dialog.getController().getConfig();
            if (newConfig == null) {
                return;
            }
            Log.d("xz", "WifiMeteredPreferenceController2 onSubmit: getWifiEntryMeteredChoice(newConfig) = " + getWifiEntryMeteredChoice(newConfig)
                    + " mWifiEntry.getMeteredChoice() = " + mWifiEntry.getMeteredChoice());
            if (getWifiEntryMeteredChoice(newConfig) != mWifiEntry.getMeteredChoice()) {
                mWifiEntry.setMeteredChoice(getWifiEntryMeteredChoice(newConfig));
                onPreferenceChange(mPreference, String.valueOf(newConfig.meteredOverride));
            }
        }
    }



@Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        if (mWifiEntry.isSaved() || mWifiEntry.isSubscription()) {
            mWifiEntry.setMeteredChoice(Integer.parseInt((String) newValue));
        }

        // Stage the backup of the SettingsProvider package which backs this up
        BackupManager.dataChanged("com.android.providers.settings");
        updateSummary((ListPreference) preference, getMeteredOverride());
        return true;
    }
@Override
    public void onSubmit(WifiDialog2 dialog) {
        Log.d("xz", "WifiPrivacyPreferenceController2 onSubmit: ");
        if (dialog.getController() != null) {
            final WifiConfiguration newConfig = dialog.getController().getConfig();
            if (newConfig == null) {
                return;
            }
            Log.d("xz", "WifiPrivacyPreferenceController2 getWifiEntryPrivacy(newConfig): " + getWifiEntryPrivacy(newConfig)
                    + " mWifiEntry.getPrivacy() = " + mWifiEntry.getPrivacy());
            if (getWifiEntryPrivacy(newConfig) != mWifiEntry.getPrivacy()) {
                mWifiEntry.setPrivacy(getWifiEntryPrivacy(newConfig));
                onPreferenceChange(mPreference, String.valueOf(newConfig.macRandomizationSetting));
            }
        }
    }


@Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        final int privacy = Integer.parseInt((String) newValue);
        mWifiEntry.setPrivacy(privacy);

        // To activate changing, we need to reconnect network. WiFi will auto connect to
        // current network after disconnect(). Only needed when this is connected network.
        if (mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) {
            mWifiEntry.disconnect(null /* callback */);
            mWifiEntry.connect(null /* callback */);
        }
        updateSummary((ListPreference) preference, privacy);
        return true;
    }

@Override
    public void onSubmit(WifiDialog2 dialog) {
        Log.d("xz", "WifiDetailPreferenceController2 onSubmit: ");
        if (dialog.getController() != null) {
            WifiConfiguration config = dialog.getController().getConfig();
            Log.d("xz", "WifiDetailPreferenceController2 onSubmit: dialog.getController().getConfig() = " + config + " password = " + config.SSID);
            mWifiManager.save(config, new WifiManager.ActionListener() {
                @Override
                public void onSuccess() {
                }

                @Override
                public void onFailure(int reason) {
                    Activity activity = mFragment.getActivity();
                    if (activity != null) {
                        Toast.makeText(activity,
                                R.string.wifi_failed_save_message,
                                Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    }

分析这3个方法,再结合现象找出可问题点。

是由于  

mWifiEntry.setMeteredChoice()
mWifiEntry.setPrivacy()

这个方法的执行导致的,当改变  隐私和 流量这两个设置时,会导致这两个方法执行 。

这两个方法去看的时候看不到具体的细节。根据现象去分析,可能是这两个方法修改了mWifiEntry的密码导致的,但是    mWifiManager.save(config, new WifiManager.ActionListener()  此保存设置的方法的执行是有用的。所以解决方案就是将mWifiManager.save(config, new WifiManager.ActionListener() 方法的执行放在后面。

在WifiNetworkDetailsFragment.java中将他们的add顺序调整一下就可以了。

mWifiDialogListeners.add(privacyController2);
        mWifiDialogListeners.add(meteredPreferenceController2);
        mWifiDialogListeners.add(mWifiDetailPreferenceController2);

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐