wifi热点_wifi热点设置已更改怎么办 - CSDN
精华内容
参与话题
  • 前言:之前主要梳理了WiFi开启扫描连接的流程,现在梳理下WiFi 热点 的开启流程。...wifi热点是将手机接收的GPRS、3G或4G信号转化为wifi信号发出去的技术,手机必须有无线AP功能,才能当做热点。有些系统自带建...

    前言:之前主要梳理了WiFi开启扫描连接的流程,现在梳理下WiFi 热点 的开启流程。

    时序图mdj样式:https://download.csdn.net/download/sinat_20059415/10542186

     

    1. wifi热点简介

     

    wifi热点是将手机接收的GPRS、3G或4G信号转化为wifi信号发出去的技术,手机必须有无线AP功能,才能当做热点。有些系统自带建热点这个功能比如 IOS(比如 iPhone 4s)。

    如果你把你的iPhone当做热点,那么像TOUCH,PAD这样有WIFI功能的,都可以搜索到你手机建立的WIFI网络,连接上以后,TOUCH等使用WIFI产生的流量上网都是消耗的乐WIFI里的手机卡的GPRS或3G流量,所以iphone里最好放一张包大流量的上网卡。还有,把手机当做热点很费电,最好用的时候插上充电器。

     

    2. WiFi热点开启流程梳理

    2.1 Settings

    Android O的Settings引入了PreferenceController这个包装类来实现对Preference的精细化控制,让代码结构更加地鲜明,很好地体现了单一职责原则,以前的Preference都是一大坨代码冗余在一起,看的都头疼。

    TetherSettings->WifiTetherPreferenceController->WifiTetherSwitchBarController

    TetherSettings是WiFi热点对应的界面,WifiTetherSwitchBarController是用来负责热点开关的相关逻辑处理的。

    /packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java

    public class WifiTetherSwitchBarController implements SwitchWidgetController.OnSwitchChangeListener,
            LifecycleObserver, OnStart, OnStop {
    ...
       @Override
        public boolean onSwitchToggled(boolean isChecked) {
            if (isChecked) {
                startTether();
            } else {
                stopTether();
            }
            return true;
        }
    
        void stopTether() {
            mSwitchBar.setEnabled(false);
            mConnectivityManager.stopTethering(TETHERING_WIFI);
        }
    
        void startTether() {
            mSwitchBar.setEnabled(false);
            mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
                    NoOpOnStartTetheringCallback.newInstance(), new Handler(Looper.getMainLooper()));
        }

    可以看到WiFi热点代开是通过ConnectivityManager的startTethering方法。

    1) callback(抽象类直接new出来的,内部实现还没有。。。)

    class NoOpOnStartTetheringCallback {
    
        public static ConnectivityManager.OnStartTetheringCallback newInstance() {
            return new ConnectivityManager.OnStartTetheringCallback() {
            };
        }   
    }
    
        /**
         * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
         * @hide
         */
        @SystemApi
        public static abstract class OnStartTetheringCallback {
            /**
             * Called when tethering has been successfully started.
             */
            public void onTetheringStarted() {}
    
            /**
             * Called when starting tethering failed.
             */
            public void onTetheringFailed() {}
        }

     

     

    2)状态监听:

     

     

        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(action)) {
                    final int state = intent.getIntExtra(
                            WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED);
                    handleWifiApStateChanged(state);
                } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
                    enableWifiSwitch();
                }
            }
        };  
    
        private void handleWifiApStateChanged(int state) {
            switch (state) {
                case WifiManager.WIFI_AP_STATE_ENABLING:
                    mSwitchBar.setEnabled(false);
                    break;
                case WifiManager.WIFI_AP_STATE_ENABLED:
                    if (!mSwitchBar.isChecked()) {
                        mSwitchBar.setChecked(true);
                    }
                    enableWifiSwitch();
                    break;
                case WifiManager.WIFI_AP_STATE_DISABLING:
                    if (mSwitchBar.isChecked()) {
                        mSwitchBar.setChecked(false);
                    }
                    mSwitchBar.setEnabled(false);
                    break;
                case WifiManager.WIFI_AP_STATE_DISABLED:
                    mSwitchBar.setChecked(false);
                    enableWifiSwitch();
                    break;
                default:
                    mSwitchBar.setChecked(false);
                    enableWifiSwitch();
                    break;
            }
        }   
    
        private void enableWifiSwitch() {
            boolean isAirplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
                    Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
            if (!isAirplaneMode) {
                mSwitchBar.setEnabled(!mDataSaverBackend.isDataSaverEnabled());
            } else {
                mSwitchBar.setEnabled(false);
            }
        }
    

     

     

     

    2.2 ConnectivityManager

     

        /**
         * Runs tether provisioning for the given type if needed and then starts tethering if
         * the check succeeds. If no carrier provisioning is required for tethering, tethering is
         * enabled immediately. If provisioning fails, tethering will not be enabled. It also
         * schedules tether provisioning re-checks if appropriate.
         *
         * @param type The type of tethering to start. Must be one of
         *         {@link ConnectivityManager.TETHERING_WIFI},
         *         {@link ConnectivityManager.TETHERING_USB}, or
         *         {@link ConnectivityManager.TETHERING_BLUETOOTH}.
         * @param showProvisioningUi a boolean indicating to show the provisioning app UI if there
         *         is one. This should be true the first time this function is called and also any time
         *         the user can see this UI. It gives users information from their carrier about the
         *         check failing and how they can sign up for tethering if possible.
         * @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller
         *         of the result of trying to tether.
         * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
         * @hide
         */
        @SystemApi
        @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
        public void startTethering(int type, boolean showProvisioningUi,
                final OnStartTetheringCallback callback, Handler handler) {
            Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
    
            ResultReceiver wrappedCallback = new ResultReceiver(handler) {
                @Override
                protected void onReceiveResult(int resultCode, Bundle resultData) {
                    if (resultCode == TETHER_ERROR_NO_ERROR) {
                        callback.onTetheringStarted();
                    } else {
                        callback.onTetheringFailed();
                    }
                }
            };
    
            try {
                String pkgName = mContext.getOpPackageName();
                Log.i(TAG, "startTethering caller:" + pkgName);
                mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName);
            } catch (RemoteException e) {
                Log.e(TAG, "Exception trying to start tethering.", e);
                wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null);
            }
        }

    至于mService:

            mConnectivityManager =
                    (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

    SystemServiceRegistry:

            registerService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class,
                    new StaticApplicationContextServiceFetcher<ConnectivityManager>() {
                @Override
                public ConnectivityManager createService(Context context) throws ServiceNotFoundException {
                    IBinder b = ServiceManager.getServiceOrThrow(Context.CONNECTIVITY_SERVICE);
                    IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
                    return new ConnectivityManager(context, service);
                }});
        /**
         * {@hide}
         */
        public ConnectivityManager(Context context, IConnectivityManager service) {
            mContext = Preconditions.checkNotNull(context, "missing context");
            mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
            sInstance = this;
        }

    SystemServer:

                    traceBeginAndSlog("StartConnectivityService");
                    try {
                        connectivity = new ConnectivityService(
                                context, networkManagement, networkStats, networkPolicy);
                        ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
                        networkStats.bindConnectivityManager(connectivity);
                        networkPolicy.bindConnectivityManager(connectivity);
                    } catch (Throwable e) {
                        reportWtf("starting Connectivity Service", e);
                    }
                    traceEnd();

     

    所以mService是ConnectivityService。

     

     

    2.3 ConnectivityService

        @Override
        public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
                String callerPkg) {
            ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
            if (!isTetheringSupported()) {
                receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
                return;
            }
            mTethering.startTethering(type, receiver, showProvisioningUi);
        }

     

    2.4 Tethering

     

        public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
            if (!isTetherProvisioningRequired()) {
                enableTetheringInternal(type, true, receiver);
                return;
            }
    
            if (showProvisioningUi) {
                runUiTetherProvisioningAndEnable(type, receiver);
            } else {
                runSilentTetherProvisioningAndEnable(type, receiver);
            }
        }

    暂时先认为打开tethering需要provision吧,继续往下看。

       /**
         * Check if the device requires a provisioning check in order to enable tethering.
         *
         * @return a boolean - {@code true} indicating tether provisioning is required by the carrier.
         */
        @VisibleForTesting
        protected boolean isTetherProvisioningRequired() {
            final TetheringConfiguration cfg = mConfig;
            if (mSystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
                    || cfg.provisioningApp.length == 0) {
                return false;
            }
            if (carrierConfigAffirmsEntitlementCheckNotRequired()) {
                return false;
            }
            return (cfg.provisioningApp.length == 2);
        }

    shouProvisioningUi由设置传入,是true

        private void runUiTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
            ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
            sendUiTetherProvisionIntent(type, proxyReceiver);
        }
        /**
         * Creates a proxy {@link ResultReceiver} which enables tethering if the provisioning result
         * is successful before firing back up to the wrapped receiver.
         *
         * @param type The type of tethering being enabled.
         * @param receiver A ResultReceiver which will be called back with an int resultCode.
         * @return The proxy receiver.
         */
        private ResultReceiver getProxyReceiver(final int type, final ResultReceiver receiver) {
            ResultReceiver rr = new ResultReceiver(null) {
                @Override
                protected void onReceiveResult(int resultCode, Bundle resultData) {
                    // If provisioning is successful, enable tethering, otherwise just send the error.
                    if (resultCode == TETHER_ERROR_NO_ERROR) {
                        enableTetheringInternal(type, true, receiver);
                    } else {
                        sendTetherResult(receiver, resultCode);
                    }
                }
            };
    
            // The following is necessary to avoid unmarshalling issues when sending the receiver
            // across processes.
            Parcel parcel = Parcel.obtain();
            rr.writeToParcel(parcel,0);
            parcel.setDataPosition(0);
            ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel);
            parcel.recycle();
            return receiverForSending;
        }
        private void sendUiTetherProvisionIntent(int type, ResultReceiver receiver) {
            Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
            intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
            intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            final long ident = Binder.clearCallingIdentity();
            try {
                mContext.startActivityAsUser(intent, UserHandle.CURRENT);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }

    Settings有如下类会接收并处理消息

            <activity android:name="TetherProvisioningActivity"
                android:exported="true"
                android:permission="android.permission.TETHER_PRIVILEGED"
                android:excludeFromRecents="true"
                android:theme="@style/Theme.ProvisioningActivity">
                <intent-filter android:priority="1">
                    <action android:name="android.settings.TETHER_PROVISIONING_UI" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>
    /**
     * Activity which acts as a proxy to the tether provisioning app for sanity checks and permission
     * restrictions. Specifically, the provisioning apps require
     * {@link android.permission.CONNECTIVITY_INTERNAL}, while this activity can be started by a caller
     * with {@link android.permission.TETHER_PRIVILEGED}.
     */
    public class TetherProvisioningActivity extends Activity {
        private static final int PROVISION_REQUEST = 0;
        private static final String TAG = "TetherProvisioningAct";
        private static final String EXTRA_TETHER_TYPE = "TETHER_TYPE";
        private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
        private ResultReceiver mResultReceiver;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            mResultReceiver = (ResultReceiver)getIntent().getParcelableExtra(
                    ConnectivityManager.EXTRA_PROVISION_CALLBACK);
    
            int tetherType = getIntent().getIntExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE,
                    ConnectivityManager.TETHERING_INVALID);
            String[] provisionApp = getResources().getStringArray(
                    com.android.internal.R.array.config_mobile_hotspot_provision_app);
    
            Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.setClassName(provisionApp[0], provisionApp[1]);
            intent.putExtra(EXTRA_TETHER_TYPE, tetherType);
            if (DEBUG) {
                Log.d(TAG, "Starting provisioning app: " + provisionApp[0] + "." + provisionApp[1]);
            }
    
            if (getPackageManager().queryIntentActivities(intent,
                    PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
                Log.e(TAG, "Provisioning app is configured, but not available.");
                mResultReceiver.send(ConnectivityManager.TETHER_ERROR_PROVISION_FAILED, null);
                finish();
                return;
            }
    
            startActivityForResultAsUser(intent, PROVISION_REQUEST, UserHandle.CURRENT);
        }   
    
        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent intent) {
            super.onActivityResult(requestCode, resultCode, intent);
            if (requestCode == PROVISION_REQUEST) {
                if (DEBUG) Log.d(TAG, "Got result from app: " + resultCode);
                int result = resultCode == Activity.RESULT_OK ?
                        ConnectivityManager.TETHER_ERROR_NO_ERROR :
                        ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
                mResultReceiver.send(result, null);
                finish();
            }
        }   
    }

    具体provision app需要vendor具体配置,看framework/base/core/res/res是空的

    ./values/config.xml:407:    <string-array translatable="false" name="config_mobile_hotspot_provision_app">
    ./values/config.xml-408-    <!--
    ./values/config.xml-409-        <item>com.example.provisioning</item>
    ./values/config.xml-410-        <item>com.example.provisioning.Activity</item>
    ./values/config.xml-411-    -->
    ./values/config.xml-412-    </string-array>

    完成后回调onActivityResult,发送ConnectivityManager.TETHER_ERROR_NO_ERROR,继续调用enableTetheringInternal方法。

            ResultReceiver rr = new ResultReceiver(null) {
                @Override
                protected void onReceiveResult(int resultCode, Bundle resultData) {
                    // If provisioning is successful, enable tethering, otherwise just send the error.
                    if (resultCode == TETHER_ERROR_NO_ERROR) {
                        enableTetheringInternal(type, true, receiver);
                    } else {
                        sendTetherResult(receiver, resultCode);
                    }
                }
            };

     

       /**
         * Enables or disables tethering for the given type. This should only be called once
         * provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
         * for the specified interface.
         */
        private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
            boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
            int result;
            switch (type) {
                case TETHERING_WIFI:
                    result = setWifiTethering(enable);
                    if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
                        scheduleProvisioningRechecks(type);
                    }
                    sendTetherResult(receiver, result);
                    break;
                case TETHERING_USB:
                    result = setUsbTethering(enable);
                    if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
                        scheduleProvisioningRechecks(type);
                    }
                    sendTetherResult(receiver, result);
                    break;
                case TETHERING_BLUETOOTH:
                    setBluetoothTethering(enable, receiver);
                    break;
                default:
                    Log.w(TAG, "Invalid tether type.");
                    sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
            }
        }

    可以看到tethering不特指WiFi热点,总体包含蓝牙WiFi热点和Usb。

    我们还是走不需要provision的流程把。。。

        private int setWifiTethering(final boolean enable) {
            int rval = TETHER_ERROR_MASTER_ERROR;
            final long ident = Binder.clearCallingIdentity();
            try {
                synchronized (mPublicSync) {
                    mWifiTetherRequested = enable;
                    final WifiManager mgr = getWifiManager();
                    if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
                        (!enable && mgr.stopSoftAp())) {
                        rval = TETHER_ERROR_NO_ERROR;
                    }
                }
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
            return rval;
        }

    这边会走到WifiManager里去,wifi config为空表示使用已有的WiFi config。后面的senTetherResult就是回调之前的receiver通知执行结果。

     

    2.5 WifiManager

        /**
         * Start SoftAp mode with the specified configuration.
         * Note that starting in access point mode disables station
         * mode operation
         * @param wifiConfig SSID, security and channel details as
         *        part of WifiConfiguration
         * @return {@code true} if the operation succeeds, {@code false} otherwise
         *
         * @hide
         */
        public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
            try {
                return mService.startSoftAp(wifiConfig);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

     

    2.6 WifiServiceImpl

     

        /**
         * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
         * @param wifiConfig SSID, security and channel details as part of WifiConfiguration
         * @return {@code true} if softap start was triggered
         * @throws SecurityException if the caller does not have permission to start softap
         */
        @Override
        public boolean startSoftAp(WifiConfiguration wifiConfig) {
            // NETWORK_STACK is a signature only permission.
            enforceNetworkStackPermission();
    
            mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
    
            synchronized (mLocalOnlyHotspotRequests) {
                // If a tethering request comes in while we have LOHS running (or requested), call stop
                // for softap mode and restart softap with the tethering config.
                if (!mLocalOnlyHotspotRequests.isEmpty()) {
                    stopSoftApInternal();
                }
    
                return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
            }
        }

     

        /**
         * Internal method to start softap mode. Callers of this method should have already checked
         * proper permissions beyond the NetworkStack permission.
         */
        private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
            mLog.trace("startSoftApInternal uid=% mode=%")
                    .c(Binder.getCallingUid()).c(mode).flush();
    
            // null wifiConfig is a meaningful input for CMD_SET_AP
            if (wifiConfig == null || isValid(wifiConfig)) {
                SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
                mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
                return true;
            }
            Slog.e(TAG, "Invalid WifiConfiguration");
            return false;
        }

    这边对空的wificonfig包装成了SoftApModeConfiguration接由WifiController处理。

        /**
         * Enqueue a message to this state machine.
         *
         * Message is ignored if state machine has quit.
         */
        public void sendMessage(int what, int arg1, int arg2, Object obj) {
            // mSmHandler can be null if the state machine has quit.
            SmHandler smh = mSmHandler;
            if (smh == null) return;
    
            smh.sendMessage(obtainMessage(what, arg1, arg2, obj));
        }

     

     

     

    2.7 WifiController

    ApStaDisabledState会对该消息进行对应的处理

                    case CMD_SET_AP:
                        if (msg.arg1 == 1) {
                            if (msg.arg2 == 0) { // previous wifi state has not been saved yet
                                mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED);
                            }
                            mWifiStateMachine.setHostApRunning((SoftApModeConfiguration) msg.obj,
                                    true);
                            transitionTo(mApEnabledState);
                        }
                        break;

     

    2.8 WifiStateMachine

     

        /**
         * TODO: doc
         */
        public void setHostApRunning(SoftApModeConfiguration wifiConfig, boolean enable) {
            if (enable) {
                sendMessage(CMD_START_AP, wifiConfig);
            } else {
                sendMessage(CMD_STOP_AP);
            }
        }

     

    看了一圈只有InitialState对该消息有正确响应

                    case CMD_START_AP:
                        transitionTo(mSoftApState);
                        break;

    InitialState exit()方法为空,看下SoftApState的enter方法

        class SoftApState extends State {
            private SoftApManager mSoftApManager;
            private String mIfaceName;
            private int mMode;
    
            private class SoftApListener implements SoftApManager.Listener {
                @Override
                public void onStateChanged(int state, int reason) {
                    if (state == WIFI_AP_STATE_DISABLED) {
                        sendMessage(CMD_AP_STOPPED);
                    } else if (state == WIFI_AP_STATE_FAILED) {
                        sendMessage(CMD_START_AP_FAILURE);
                    }
    
                    setWifiApState(state, reason, mIfaceName, mMode);
                }
            }
    
            @Override
            public void enter() {
                final Message message = getCurrentMessage();
                if (message.what != CMD_START_AP) {
                    throw new RuntimeException("Illegal transition to SoftApState: " + message);
                }
                SoftApModeConfiguration config = (SoftApModeConfiguration) message.obj;
                mMode = config.getTargetMode();
    
                IApInterface apInterface = null;
                Pair<Integer, IApInterface> statusAndInterface = mWifiNative.setupForSoftApMode();
                if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) {
                    apInterface = statusAndInterface.second;
                } else {
                    incrementMetricsForSetupFailure(statusAndInterface.first);
                }
                if (apInterface == null) {
                    setWifiApState(WIFI_AP_STATE_FAILED,
                            WifiManager.SAP_START_FAILURE_GENERAL, null, mMode);
                    /**
                     * Transition to InitialState to reset the
                     * driver/HAL back to the initial state.
                     */
                    transitionTo(mInitialState);
                    return;
                }
    
                try {
                    mIfaceName = apInterface.getInterfaceName();
                } catch (RemoteException e) {
                    // Failed to get the interface name. The name will not be available for
                    // the enabled broadcast, but since we had an error getting the name, we most likely
                    // won't be able to fully start softap mode.
                }
    
                checkAndSetConnectivityInstance();
                mSoftApManager = mWifiInjector.makeSoftApManager(mNwService,
                                                                 new SoftApListener(),
                                                                 apInterface,
                                                                 config.getWifiConfiguration());
                mSoftApManager.start();
                mWifiStateTracker.updateState(WifiStateTracker.SOFT_AP);
            }
    
    
    这边的调用流程和WiFi的启动流程有点类似。先梳理到这,后面应该是硬菜。。。

     

    3. 总结

    展开全文
  • Wifi热点实现文件传输

    热门讨论 2020-07-29 14:20:39
    通过wifi热点和wifi连接实现手机对手机的文件传输,功能已经实现,锦上添花的事自己去完成吧!
  • android的热点功能不可见,用了反射的技术搞定之外。 Eclipse设置语言为utf-8才能查看中文注释 上代码: MainActivity.java p
    原文地址为:Android 连接Wifi和创建Wifi热点 demo

    android的热点功能不可见,用了反射的技术搞定之外。
    Eclipse设置语言为utf-8才能查看中文注释

    上代码:

    MainActivity.java

    package com.widget.hotspot;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.util.Log;
    import android.view.Menu;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends Activity {
    
    	public static final String TAG = "MainActivity";
    	
    	private Button mBtn1, mBtn2;
    	
    	private WifiAdmin mWifiAdmin;
    	
    	private Context mContext = null;
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		
    		mContext = this;
    		
    		setContentView(R.layout.activity_main);
    		
    		mBtn1 = (Button)findViewById(R.id.button1);
    		mBtn2 = (Button)findViewById(R.id.button2);
    		mBtn1.setText("点击连接Wifi");
    		mBtn2.setText("点击创建Wifi热点");
    		mBtn1.setOnClickListener(new Button.OnClickListener() {
    			
    			@Override
    			public void onClick(View v) {
    				// TODO Auto-generated method stub
    
    				mWifiAdmin = new WifiAdmin(mContext) {
    					
    					@Override
    					public void myUnregisterReceiver(BroadcastReceiver receiver) {
    						// TODO Auto-generated method stub
    						MainActivity.this.unregisterReceiver(receiver);
    					}
    					
    					@Override
    					public Intent myRegisterReceiver(BroadcastReceiver receiver,
    							IntentFilter filter) {
    						// TODO Auto-generated method stub
    						MainActivity.this.registerReceiver(receiver, filter);
    						return null;
    					}
    					
    					@Override
    					public void onNotifyWifiConnected() {
    						// TODO Auto-generated method stub
    						Log.v(TAG, "have connected success!");
    						Log.v(TAG, "###############################");
    					}
    					
    					@Override
    					public void onNotifyWifiConnectFailed() {
    						// TODO Auto-generated method stub
    						Log.v(TAG, "have connected failed!");
    						Log.v(TAG, "###############################");
    					}
    				};
    				mWifiAdmin.openWifi();
    				mWifiAdmin.addNetwork(mWifiAdmin.createWifiInfo("YOU_WIFI", "MM123456", WifiAdmin.TYPE_WPA));
    				
    			}
    		});
    		
    		mBtn2.setOnClickListener(new Button.OnClickListener() {
    			
    			@Override
    			public void onClick(View v) {
    				// TODO Auto-generated method stub
    				
    				WifiApAdmin wifiAp = new WifiApAdmin(mContext);
    				wifiAp.startWifiAp("\"HotSpot\"", "hhhhhh123");
    			}
    		});
    		
    	}
    
    	@Override
    	public boolean onCreateOptionsMenu(Menu menu) {
    		// Inflate the menu; this adds items to the action bar if it is present.
    		getMenuInflater().inflate(R.menu.activity_main, menu);
    		return true;
    	}
    
    	 @Override
    	    public void onResume() {
    	        super.onResume();
    	        
    	        Log.d("Rssi", "Registered");
    	    }
    
    	    @Override
    	    public void onPause() {
    	        super.onPause();
    	        
    	        Log.d("Rssi", "Unregistered");
    	    }
    	
    }
    


    WifiAdmin.java

    参考了://http://blog.csdn.net/yuanbohx/article/details/8109042

    package com.widget.hotspot;
    
    import java.util.List;
    import java.util.Timer;
    import java.util.TimerTask;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.net.ConnectivityManager;
    import android.net.NetworkInfo;
    import android.net.NetworkInfo.DetailedState;
    import android.net.wifi.ScanResult;
    import android.net.wifi.WifiConfiguration;
    import android.net.wifi.WifiInfo;
    import android.net.wifi.WifiManager;
    import android.net.wifi.WifiManager.WifiLock;
    import android.util.Log;
    
    
    public abstract class WifiAdmin {
    	
    	private static final String TAG = "WifiAdmin";
    	
    	private WifiManager mWifiManager;
    	private WifiInfo mWifiInfo;
    	// 扫描出的网络连接列表
    	private List<ScanResult> mWifiList;
    	private List<WifiConfiguration> mWifiConfiguration;
    
    	private WifiLock mWifiLock;
    	
    	private String mPasswd = "";
    	private String mSSID = "";
    	
    	private Context mContext = null;
    
    	public WifiAdmin(Context context) {
    		
    		mContext = context;
    		
    		// 取得WifiManager对象
    		mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    		// 取得WifiInfo对象
    		mWifiInfo = mWifiManager.getConnectionInfo();
    		
    		Log.v(TAG, "getIpAddress = " + mWifiInfo.getIpAddress());
    	}
    
    	// 打开WIFI
    	public void openWifi() {
    		if (!mWifiManager.isWifiEnabled()) {
    			mWifiManager.setWifiEnabled(true);
    		}
    	}
    
    	// 关闭WIFI
    	public void closeWifi() {
    		if (mWifiManager.isWifiEnabled()) {
    			mWifiManager.setWifiEnabled(false);
    		}
    	}
    
        public abstract Intent myRegisterReceiver(BroadcastReceiver receiver, IntentFilter filter);
        
        public abstract void myUnregisterReceiver(BroadcastReceiver receiver);
        
        public abstract void onNotifyWifiConnected();
        
        public abstract void onNotifyWifiConnectFailed();
    	
    	// 添加一个网络并连接
    	public void addNetwork(WifiConfiguration wcg) {
    		
    		register();
    		
    		WifiApAdmin.closeWifiAp(mContext);
    		
    		int wcgID = mWifiManager.addNetwork(wcg);
    		boolean b = mWifiManager.enableNetwork(wcgID, true);
    	}
    	
    	public static final int TYPE_NO_PASSWD = 0x11;
    	public static final int TYPE_WEP = 0x12;
    	public static final int TYPE_WPA = 0x13;
    	
    	public void addNetwork(String ssid, String passwd, int type) {
    		if (ssid == null || passwd == null || ssid.equals("")) {
    			Log.e(TAG, "addNetwork() ## nullpointer error!");
    			return;
    		}
    		
    		if (type != TYPE_NO_PASSWD && type != TYPE_WEP && type != TYPE_WPA) {
    			Log.e(TAG, "addNetwork() ## unknown type = " + type);
    		}
    		
    		stopTimer();
    		unRegister();
    		
    		addNetwork(createWifiInfo(ssid, passwd, type));
    	}
    
    	private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    
    		@Override
    		public void onReceive(Context context, Intent intent) {
    			// TODO Auto-generated method stub
    			if (intent.getAction().equals(WifiManager.RSSI_CHANGED_ACTION)) {
    				Log.d(TAG, "RSSI changed");
    				
    				//有可能是正在获取,或者已经获取了
    				Log.d(TAG, " intent is " + WifiManager.RSSI_CHANGED_ACTION);
    				
    				if (isWifiContected(mContext) == WIFI_CONNECTED) {
    					stopTimer();
    					onNotifyWifiConnected();
    					unRegister();
    				} else if (isWifiContected(mContext) == WIFI_CONNECT_FAILED) {
    					stopTimer();
    					closeWifi();
    					onNotifyWifiConnectFailed();
    					unRegister();
    				} else if (isWifiContected(mContext) == WIFI_CONNECTING) {
    					
    				}
    			}
    		}
    	};
    	
    	private final int STATE_REGISTRING = 0x01;
    	private final int STATE_REGISTERED = 0x02;
    	private final int STATE_UNREGISTERING = 0x03;
    	private final int STATE_UNREGISTERED = 0x04;
    	
    	private int mHaveRegister = STATE_UNREGISTERED;
    	private synchronized void register() {
    		Log.v(TAG, "register() ##mHaveRegister = " + mHaveRegister);
    
    		if (mHaveRegister == STATE_REGISTRING 
    				|| mHaveRegister == STATE_REGISTERED) {
    			return ;
    		}
    		
    		mHaveRegister = STATE_REGISTRING;
    		myRegisterReceiver(mBroadcastReceiver, new IntentFilter(WifiManager.RSSI_CHANGED_ACTION));
    		mHaveRegister = STATE_REGISTERED;
    		
    		startTimer();
    	}
    	
    	private synchronized void unRegister() {
    		Log.v(TAG, "unRegister() ##mHaveRegister = " + mHaveRegister);
    		
    		if (mHaveRegister == STATE_UNREGISTERED 
    				|| mHaveRegister == STATE_UNREGISTERING) {
    			return ;
    		}
    		
    		mHaveRegister = STATE_UNREGISTERING;
    		myUnregisterReceiver(mBroadcastReceiver);
    		mHaveRegister = STATE_UNREGISTERED;
    	}
    	
    	private Timer mTimer = null;
    	private void startTimer() {
    		if (mTimer != null) {
    			stopTimer();
    		}
    		
    		mTimer = new Timer(true);
    //		mTimer.schedule(mTimerTask, 0, 20 * 1000);// 20s
    		mTimer.schedule(mTimerTask, 30 * 1000);
    	}
    	
    	private TimerTask mTimerTask = new TimerTask() {
    		
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			Log.e(TAG, "timer out!");
    			onNotifyWifiConnectFailed();
    			unRegister();
    		}
    	};
    	
    	private void stopTimer() {
    		if (mTimer != null) {
    			mTimer.cancel();
    			mTimer = null;
    		}
    	}
    	
    	@Override
    	protected void finalize() {
    		try {
    			super.finalize();
    			unRegister();
    		} catch (Throwable e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    	
    	public WifiConfiguration createWifiInfo(String SSID, String password, int type) {
    		
    		Log.v(TAG, "SSID = " + SSID + "## Password = " + password + "## Type = " + type);
    		
    		WifiConfiguration config = new WifiConfiguration();
    		config.allowedAuthAlgorithms.clear();
    		config.allowedGroupCiphers.clear();
    		config.allowedKeyManagement.clear();
    		config.allowedPairwiseCiphers.clear();
    		config.allowedProtocols.clear();
    		config.SSID = "\"" + SSID + "\"";
    
    		WifiConfiguration tempConfig = this.IsExsits(SSID);
    		if (tempConfig != null) {
    			mWifiManager.removeNetwork(tempConfig.networkId);
    		}
    		
    		// 分为三种情况:1没有密码2用wep加密3用wpa加密
    		if (type == TYPE_NO_PASSWD) {// WIFICIPHER_NOPASS
    			config.wepKeys[0] = "";
    			config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
    			config.wepTxKeyIndex = 0;
    			
    		} else if (type == TYPE_WEP) {  //  WIFICIPHER_WEP 
    			config.hiddenSSID = true;
    			config.wepKeys[0] = "\"" + password + "\"";
    			config.allowedAuthAlgorithms
    					.set(WifiConfiguration.AuthAlgorithm.SHARED);
    			config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
    			config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
    			config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
    			config.allowedGroupCiphers
    					.set(WifiConfiguration.GroupCipher.WEP104);
    			config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
    			config.wepTxKeyIndex = 0;
    		} else if (type == TYPE_WPA) {   // WIFICIPHER_WPA
    			config.preSharedKey = "\"" + password + "\"";
    			config.hiddenSSID = true;
    			config.allowedAuthAlgorithms
    					.set(WifiConfiguration.AuthAlgorithm.OPEN);
    			config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
    			config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
    			config.allowedPairwiseCiphers
    					.set(WifiConfiguration.PairwiseCipher.TKIP);
    			// config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
    			config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
    			config.allowedPairwiseCiphers
    					.set(WifiConfiguration.PairwiseCipher.CCMP);
    			config.status = WifiConfiguration.Status.ENABLED;
    		} 
    		
    		return config;
    	}
    	
    	public static final int WIFI_CONNECTED = 0x01;
    	public static final int WIFI_CONNECT_FAILED = 0x02;
    	public static final int WIFI_CONNECTING = 0x03;
    	/**
    	 * 判断wifi是否连接成功,不是network
    	 * 
    	 * @param context
    	 * @return
    	 */
    	public int isWifiContected(Context context) {
    		ConnectivityManager connectivityManager = (ConnectivityManager) context
    				.getSystemService(Context.CONNECTIVITY_SERVICE);
    		NetworkInfo wifiNetworkInfo = connectivityManager
    				.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
    		
    		Log.v(TAG, "isConnectedOrConnecting = " + wifiNetworkInfo.isConnectedOrConnecting());
    		Log.d(TAG, "wifiNetworkInfo.getDetailedState() = " + wifiNetworkInfo.getDetailedState());
    		if (wifiNetworkInfo.getDetailedState() == DetailedState.OBTAINING_IPADDR
    				|| wifiNetworkInfo.getDetailedState() == DetailedState.CONNECTING) {
    			return WIFI_CONNECTING;
    		} else if (wifiNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
    			return WIFI_CONNECTED;
    		} else {
    			Log.d(TAG, "getDetailedState() == " + wifiNetworkInfo.getDetailedState());
    			return WIFI_CONNECT_FAILED;
    		}
    	}
    	
    	private WifiConfiguration IsExsits(String SSID) {
    		List<WifiConfiguration> existingConfigs = mWifiManager.getConfiguredNetworks();
    		for (WifiConfiguration existingConfig : existingConfigs) {
    			if (existingConfig.SSID.equals("\"" + SSID + "\"") /*&& existingConfig.preSharedKey.equals("\"" + password + "\"")*/) {
    				return existingConfig;
    			}
    		}
    		return null;
    	}
    	
    
    
    	// 断开指定ID的网络
    	public void disconnectWifi(int netId) {
    		mWifiManager.disableNetwork(netId);
    		mWifiManager.disconnect();
    	}
    	
    	// 检查当前WIFI状态
    	public int checkState() {
    		return mWifiManager.getWifiState();
    	}
    
    	// 锁定WifiLock
    	public void acquireWifiLock() {
    		mWifiLock.acquire();
    	}
    
    	// 解锁WifiLock
    	public void releaseWifiLock() {
    		// 判断时候锁定
    		if (mWifiLock.isHeld()) {
    			mWifiLock.acquire();
    		}
    	}
    
    	// 创建一个WifiLock
    	public void creatWifiLock() {
    		mWifiLock = mWifiManager.createWifiLock("Test");
    	}
    
    	// 得到配置好的网络
    	public List<WifiConfiguration> getConfiguration() {
    		return mWifiConfiguration;
    	}
    
    	// 指定配置好的网络进行连接
    	public void connectConfiguration(int index) {
    		// 索引大于配置好的网络索引返回
    		if (index > mWifiConfiguration.size()) {
    			return;
    		}
    		// 连接配置好的指定ID的网络
    		mWifiManager.enableNetwork(mWifiConfiguration.get(index).networkId,
    				true);
    	}
    
    	public void startScan() {
    		mWifiManager.startScan();
    		mWifiList = mWifiManager.getScanResults();
    		mWifiConfiguration = mWifiManager.getConfiguredNetworks();
    	}
    
    	// 得到网络列表
    	public List<ScanResult> getWifiList() {
    		return mWifiList;
    	}
    
    	// 查看扫描结果
    	public StringBuilder lookUpScan() {
    		StringBuilder stringBuilder = new StringBuilder();
    		for (int i = 0; i < mWifiList.size(); i++) {
    			stringBuilder
    					.append("Index_" + new Integer(i + 1).toString() + ":");
    			// 将ScanResult信息转换成一个字符串包
    			// 其中把包括:BSSID、SSID、capabilities、frequency、level
    			stringBuilder.append((mWifiList.get(i)).toString());
    			stringBuilder.append("/n");
    		}
    		return stringBuilder;
    	}
    
    	// 得到MAC地址
    	public String getMacAddress() {
    		return (mWifiInfo == null) ? "NULL" : mWifiInfo.getMacAddress();
    	}
    
    	// 得到接入点的BSSID
    	public String getBSSID() {
    		return (mWifiInfo == null) ? "NULL" : mWifiInfo.getBSSID();
    	}
    
    	// 得到IP地址
    	public int getIPAddress() {
    		return (mWifiInfo == null) ? 0 : mWifiInfo.getIpAddress();
    	}
    
    	// 得到连接的ID
    	public int getNetworkId() {
    		return (mWifiInfo == null) ? 0 : mWifiInfo.getNetworkId();
    	}
    
    	// 得到WifiInfo的所有信息包
    	public String getWifiInfo() {
    		return (mWifiInfo == null) ? "NULL" : mWifiInfo.toString();
    	}
    }
    


    WifiApAdmin.java

    参考了 http://blog.csdn.net/cxlmax/article/details/7827102

    package com.widget.hotspot;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.Timer;
    import java.util.TimerTask;
    
    import android.content.Context;
    import android.net.wifi.WifiConfiguration;
    import android.net.wifi.WifiManager;
    import android.util.Log;
    
    /**
     * 创建热点
     *
     */
    public class WifiApAdmin {
    	public static final String TAG = "WifiApAdmin";
    	
    	public static void closeWifiAp(Context context) {
    		WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 
    		closeWifiAp(wifiManager);
    	}
    	
    	private WifiManager mWifiManager = null;
    	
    	private Context mContext = null;
    	public WifiApAdmin(Context context) {
    		mContext = context;
    		
    		mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);  
    		
    		closeWifiAp(mWifiManager);
    	}
    	
    	private String mSSID = "";
    	private String mPasswd = "";
    	public void startWifiAp(String ssid, String passwd) {
    		mSSID = ssid;
    		mPasswd = passwd;
    		
    		if (mWifiManager.isWifiEnabled()) {
    			mWifiManager.setWifiEnabled(false);
    		} 
    		
    		stratWifiAp();
    		
    		MyTimerCheck timerCheck = new MyTimerCheck() {
    			
    			@Override
    			public void doTimerCheckWork() {
    				// TODO Auto-generated method stub
    				
    				if (isWifiApEnabled(mWifiManager)) {
    					Log.v(TAG, "Wifi enabled success!");
    					this.exit();
    				} else {
    					Log.v(TAG, "Wifi enabled failed!");
    				}
    			}
    
    			@Override
    			public void doTimeOutWork() {
    				// TODO Auto-generated method stub
    				this.exit();
    			}
    		};
    		timerCheck.start(15, 1000);
    		
    	}
    
    	public void stratWifiAp() {
    		Method method1 = null;
    		try {
    			method1 = mWifiManager.getClass().getMethod("setWifiApEnabled",
    					WifiConfiguration.class, boolean.class);
    			WifiConfiguration netConfig = new WifiConfiguration();
    
    			netConfig.SSID = mSSID;
    			netConfig.preSharedKey = mPasswd;
    
    			netConfig.allowedAuthAlgorithms
    					.set(WifiConfiguration.AuthAlgorithm.OPEN);
    			netConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
    			netConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
    			netConfig.allowedKeyManagement
    					.set(WifiConfiguration.KeyMgmt.WPA_PSK);
    			netConfig.allowedPairwiseCiphers
    					.set(WifiConfiguration.PairwiseCipher.CCMP);
    			netConfig.allowedPairwiseCiphers
    					.set(WifiConfiguration.PairwiseCipher.TKIP);
    			netConfig.allowedGroupCiphers
    					.set(WifiConfiguration.GroupCipher.CCMP);
    			netConfig.allowedGroupCiphers
    					.set(WifiConfiguration.GroupCipher.TKIP);
    
    			method1.invoke(mWifiManager, netConfig, true);
    
    		} catch (IllegalArgumentException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (InvocationTargetException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (SecurityException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (NoSuchMethodException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    
    	private static void closeWifiAp(WifiManager wifiManager) {
    		if (isWifiApEnabled(wifiManager)) {
    			try {
    				Method method = wifiManager.getClass().getMethod("getWifiApConfiguration");
    				method.setAccessible(true);
    
    				WifiConfiguration config = (WifiConfiguration) method.invoke(wifiManager);
    
    				Method method2 = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
    				method2.invoke(wifiManager, config, false);
    			} catch (NoSuchMethodException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			} catch (IllegalArgumentException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			} catch (IllegalAccessException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			} catch (InvocationTargetException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	}
    
    	private static boolean isWifiApEnabled(WifiManager wifiManager) {
    		try {
    			Method method = wifiManager.getClass().getMethod("isWifiApEnabled");
    			method.setAccessible(true);
    			return (Boolean) method.invoke(wifiManager);
    
    		} catch (NoSuchMethodException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    
    		return false;
    	}
    
    }
    


    MyTimeCheck.java

    package com.widget.hotspot;
    
    
    public abstract class MyTimerCheck {
    	private int mCount = 0;
    	private int mTimeOutCount = 1;
    	private int mSleepTime = 1000; // 1s
    	private boolean mExitFlag = false;
    	private Thread mThread = null;
    	
    	/**
    	 * Do not process UI work in this.
    	 */
    	public abstract void doTimerCheckWork();
    	
    	public abstract void doTimeOutWork();
    	
    	public MyTimerCheck() {
    		mThread = new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				// TODO Auto-generated method stub
    				while (!mExitFlag) {
    					mCount++;
    					if (mCount < mTimeOutCount) {
    						doTimerCheckWork();
    						try {
    							mThread.sleep(mSleepTime);
    						} catch (InterruptedException e) {
    							// TODO Auto-generated catch block
    							e.printStackTrace();
    							exit();
    						}
    					} else {
    						doTimeOutWork();
    					}
    				}
    			}
    		});
    	}
    	
    	/**
    	 * start
    	 * @param times  How many times will check?
    	 * @param sleepTime ms, Every check sleep time.
    	 */
    	public void start(int timeOutCount, int sleepTime) {
    		mTimeOutCount = timeOutCount;
    		mSleepTime = sleepTime;
    		
    		mThread.start();
    	}
    	
    	public void exit() {
    		mExitFlag = true;
    	}
    	
    }
    

    xml布局简单不上了,

    效果自己试试看打印就知道了







    转载请注明本文地址:Android 连接Wifi和创建Wifi热点 demo
    展开全文
  • Android WiFi开发 (二)Wifi热点

    万次阅读 热门讨论 2020-02-17 14:20:05
    接着上一篇wifi的扫描连接等,这一篇主要说一下手机开启Wifi热点。 demo的下载地址会在最下面贴出来。 图片: 经测试开启wifi热点(无秘密,wpa安全类型,wpa2安全类型)都可以正常开启并使用。 主要用到的代码...

    接着上一篇wifi的扫描连接等,这一篇主要说一下手机开启Wifi热点。

    demo的下载地址会在最下面贴出来。

    图片:

           

    1 创建WIFI热点

    经测试开启wifi热点(无秘密,wpa安全类型,wpa2安全类型)都可以正常开启并使用。

    需要注意的是wifi和wifi热点不能同时打开,也就是连接wifi的时候,开启热点需要先将wifi关闭才可以。

    用到的主要代码:

     

    package com.vn.wifitest.utils;
    
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.net.wifi.WifiConfiguration;
    import android.net.wifi.WifiConfiguration.KeyMgmt;
    import android.net.wifi.WifiManager;
    import android.os.Handler;
    import android.util.Log;
    
    public class WifiAPUtil {
        private static final String TAG = "WifiAPUtil";
        public final static boolean DEBUG = true;
    
        public static final int MESSAGE_AP_STATE_ENABLED = 1;
        public static final int MESSAGE_AP_STATE_FAILED = 2;
    	//默认wifi秘密
        private static final String DEFAULT_AP_PASSWORD = "12345678";	
        private static WifiAPUtil sInstance;
        private static Handler mHandler;
        private static Context mContext;
        private WifiManager mWifiManager;
    	//监听wifi热点的状态变化
        public static final String WIFI_AP_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED";
        public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
        public static int WIFI_AP_STATE_DISABLING = 10;
        public static int WIFI_AP_STATE_DISABLED = 11;
        public static int WIFI_AP_STATE_ENABLING = 12;
        public static int WIFI_AP_STATE_ENABLED = 13;
        public static int WIFI_AP_STATE_FAILED = 14;
    	public enum WifiSecurityType {
    		WIFICIPHER_NOPASS, WIFICIPHER_WPA, WIFICIPHER_WEP, WIFICIPHER_INVALID, WIFICIPHER_WPA2
    	}
    	private WifiAPUtil(Context context) {
    		if(DEBUG) Log.d(TAG,"WifiAPUtils construct"); 
    		mContext = context;
    		mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    		IntentFilter filter = new IntentFilter();
    		filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
    		context.registerReceiver(mWifiStateBroadcastReceiver, filter);
    	}
    	protected void finalize() {
    		if(DEBUG) Log.d(TAG,"finalize");
    		mContext.unregisterReceiver(mWifiStateBroadcastReceiver);
    
    }
    	public static WifiAPUtil getInstance(Context c) {
    		if (null == sInstance)
    		    sInstance = new WifiAPUtil(c);
    		return sInstance;
    	}
    
    	public boolean turnOnWifiAp(String str, String password,WifiSecurityType Type) {
    		String ssid = str;
    		//配置热点信息。
    		WifiConfiguration wcfg = new WifiConfiguration();
    		wcfg.SSID = new String(ssid);
    		wcfg.networkId = 1;
    		wcfg.allowedAuthAlgorithms.clear();
    		wcfg.allowedGroupCiphers.clear();
    		wcfg.allowedKeyManagement.clear();
    		wcfg.allowedPairwiseCiphers.clear();
    		wcfg.allowedProtocols.clear();
    		
    		if(Type == WifiSecurityType.WIFICIPHER_NOPASS) {
    			if(DEBUG)Log.d(TAG, "wifi ap----no password");
    			wcfg.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN, true);
    			wcfg.wepKeys[0] = "";    
    			wcfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);    
    			wcfg.wepTxKeyIndex = 0;
    		} else if(Type == WifiSecurityType.WIFICIPHER_WPA) {
    			if(DEBUG)Log.d(TAG, "wifi ap----wpa");
    			//密码至少8位,否则使用默认密码
    			if(null != password && password.length() >= 8){
    				wcfg.preSharedKey = password;
    			} else {
    				wcfg.preSharedKey = DEFAULT_AP_PASSWORD;
    			}
    			wcfg.hiddenSSID = false;       
    			wcfg.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);       
    			wcfg.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);                             
    			wcfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);     
    			//wcfg.allowedKeyManagement.set(4);
    			wcfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);                        
    			wcfg.allowedProtocols.set(WifiConfiguration.Protocol.WPA);      
    			wcfg.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);    
    			wcfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);    
    		} else if(Type == WifiSecurityType.WIFICIPHER_WPA2) {
    			if(DEBUG)Log.d(TAG, "wifi ap---- wpa2");
    			//密码至少8位,否则使用默认密码
    			if(null != password && password.length() >= 8){
    				wcfg.preSharedKey = password;
    			} else {
    				wcfg.preSharedKey = DEFAULT_AP_PASSWORD;
    			}     
    			wcfg.hiddenSSID = true;       
    			wcfg.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);       
    			wcfg.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);                             
    			wcfg.allowedKeyManagement.set(4);     
    			//wcfg.allowedKeyManagement.set(4);
    			wcfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);                        
    			wcfg.allowedProtocols.set(WifiConfiguration.Protocol.WPA);      
    			wcfg.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);    
    			wcfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);    
    		}		
    		try {
    			Method method = mWifiManager.getClass().getMethod("setWifiApConfiguration", 
    									  wcfg.getClass());
    			Boolean rt = (Boolean)method.invoke(mWifiManager, wcfg);
    			if(DEBUG) Log.d(TAG, " rt = " + rt);
    		} catch (NoSuchMethodException e) {
    			Log.e(TAG, e.getMessage());
    		} catch (IllegalArgumentException e) {
    			Log.e(TAG, e.getMessage());
    		} catch (IllegalAccessException e) {
    			Log.e(TAG, e.getMessage());
    		} catch (InvocationTargetException e) {
    			Log.e(TAG, e.getMessage());
    		}
    		return setWifiApEnabled();
    	}
    	//获取热点状态	
    	public int getWifiAPState() {
    		int state = -1;
    		try {
    			Method method2 = mWifiManager.getClass().getMethod("getWifiApState");
    			state = (Integer) method2.invoke(mWifiManager);
    		} catch (Exception e) {
    			Log.e(TAG, e.getMessage());
    		}
    		if(DEBUG)Log.i("WifiAP", "getWifiAPState.state " + state);
    		return state;
    	}
    	
    	private boolean setWifiApEnabled() {		
    		//开启wifi热点需要关闭wifi
    		while(mWifiManager.getWifiState() != WifiManager.WIFI_STATE_DISABLED){
    			mWifiManager.setWifiEnabled(false);
    			try {
    				Thread.sleep(200);
    			} catch (Exception e) {
    				Log.e(TAG, e.getMessage());
    				return false;
    			}
    		}
    		// 确保wifi 热点关闭。
    		while(getWifiAPState() != WIFI_AP_STATE_DISABLED){
    			try {
    			Method method1 = mWifiManager.getClass().getMethod("setWifiApEnabled",
    					   WifiConfiguration.class, boolean.class);
                method1.invoke(mWifiManager, null, false);
    		
    				Thread.sleep(200);
    			} catch (Exception e) {
    				Log.e(TAG, e.getMessage());
    					return false;
    			}
    		}
    		
    		//开启wifi热点
    		try {
    		Method method1 = mWifiManager.getClass().getMethod("setWifiApEnabled",
    					   WifiConfiguration.class, boolean.class);
    		method1.invoke(mWifiManager, null, true);		
    				Thread.sleep(200);
    			} catch (Exception e) {
    				Log.e(TAG, e.getMessage());
    					return false;
    			}
    		return true;
    	}	
         //关闭WiFi热点   
        public void closeWifiAp() {        
            if (getWifiAPState() != WIFI_AP_STATE_DISABLED) {    
                try {    
                    Method method = mWifiManager.getClass().getMethod("getWifiApConfiguration");    
                    method.setAccessible(true);    
                    WifiConfiguration config = (WifiConfiguration) method.invoke(mWifiManager);    
                    Method method2 = mWifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);    
                    method2.invoke(mWifiManager, config, false);    
                } catch (NoSuchMethodException e) {    
                    e.printStackTrace();    
                } catch (IllegalArgumentException e) {    
                    e.printStackTrace();    
                } catch (IllegalAccessException e) {    
                    e.printStackTrace();    
                } catch (InvocationTargetException e) {    
                    e.printStackTrace();    
                }    
            }   
        }  
    
    	public void regitsterHandler(Handler handler){
    		mHandler = handler;
    	}
    	public void unregitsterHandler(){
    		mHandler = null;
    	}
    	//监听wifi热点状态变化
        private BroadcastReceiver mWifiStateBroadcastReceiver = new BroadcastReceiver() {			
    	    @Override
    		public void onReceive(Context context, Intent intent) {
    		if(DEBUG)Log.i(TAG,"WifiAPUtils onReceive: "+intent.getAction());
    		if(WIFI_AP_STATE_CHANGED_ACTION.equals(intent.getAction())) {
    		    int cstate = intent.getIntExtra(EXTRA_WIFI_AP_STATE, -1);
    		    if(cstate == WIFI_AP_STATE_ENABLED) {
    		    	if(mHandler != null){
    		    		mHandler.sendEmptyMessage(MESSAGE_AP_STATE_ENABLED);			    
    		    	}
    		    }if(cstate == WIFI_AP_STATE_DISABLED  || cstate == WIFI_AP_STATE_FAILED) {
    			if(mHandler != null)
    			    mHandler.sendEmptyMessage(MESSAGE_AP_STATE_FAILED);
    		    }
    		}
    	    }
    	};
    	//获取热点ssid
    	public String getValidApSsid() {
    		try {
    			Method method = mWifiManager.getClass().getMethod("getWifiApConfiguration");
    			WifiConfiguration configuration = (WifiConfiguration)method.invoke(mWifiManager);
    			return configuration.SSID;	
    		} catch (Exception e) {
    				Log.e(TAG, e.getMessage());
    				return null;
    				}
    	}
    	//获取热点密码
    	public String getValidPassword(){
    		try {
    			Method method = mWifiManager.getClass().getMethod("getWifiApConfiguration");
    			WifiConfiguration configuration = (WifiConfiguration)method.invoke(mWifiManager);
    			return configuration.preSharedKey;	
    		} catch (Exception e) {
    				Log.e(TAG, e.getMessage());
    				return null;
    				}
    	
    	}
    	//获取热点安全类型
    	public int getValidSecurity(){
    		WifiConfiguration configuration;
    		try {
    			Method method = mWifiManager.getClass().getMethod("getWifiApConfiguration");
    			configuration = (WifiConfiguration)method.invoke(mWifiManager);
    		} catch (Exception e) {
    				Log.e(TAG, e.getMessage());
    				return WifiSecurityType.WIFICIPHER_INVALID.ordinal();
    				}
    		
    		if(DEBUG)Log.i(TAG,"getSecurity security="+configuration.allowedKeyManagement);
    		if(configuration.allowedKeyManagement.get(KeyMgmt.NONE)) {
    			return WifiSecurityType.WIFICIPHER_NOPASS.ordinal();
    		}else if(configuration.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
    			return WifiSecurityType.WIFICIPHER_WPA.ordinal();
    		}else if(configuration.allowedKeyManagement.get(4)) { //4 means WPA2_PSK 
    			return WifiSecurityType.WIFICIPHER_WPA2.ordinal();
    		}
    		return WifiSecurityType.WIFICIPHER_INVALID.ordinal();
    	}
    }


    使用方法:

     

    Activity生命周期中

     

    //初始化WifiAPUtil类
    WifiAPUtil.getInstance(getApplicationContext())
    //注册handler
    WifiAPUtil.getInstance(this).regitsterHandler(mHandler);
    //接收message,做处理
    private Handler mHandler = new Handler(){
    	public void handleMessage(Message msg) {
    		switch (msg.what) {
    			case WifiAPUtil.MESSAGE_AP_STATE_ENABLED:
    	    		String ssid = WifiAPUtil.getInstance(WifiApActivity.this).getValidApSsid();
    				String pw = WifiAPUtil.getInstance(WifiApActivity.this).getValidPassword();
    				int security = WifiAPUtil.getInstance(WifiApActivity.this).getValidSecurity();
    				mWifiApState.setText("wifi热点开启成功"+"\n"
    						+"SSID = "+ssid+"\n"
    						+"Password = "+pw +"\n"
    						+"Security = "+security);
    				break;
    			case WifiAPUtil.MESSAGE_AP_STATE_FAILED:
    				mWifiApState.setText("wifi热点关闭");
    				break;
    			default:
    				break;
    		}
    	}
    };

    在activity销毁的时候

     

    @Override
    protected void onDestroy() {
    	super.onDestroy();
    	WifiAPUtil.getInstance(this).unregitsterHandler();
    }

    添加点击事件

     

     

     

    //开启wifi热点
    WifiAPUtil.getInstance(WifiApActivity.this).turnOnWifiAp(ssid, password, mWifiType);

     

     

    //关闭wifi热点
    WifiAPUtil.getInstance(WifiApActivity.this).closeWifiAp();

     

    2 监听热点的状态

    当wifi热点状态发送变化,系统会发送广播 android.net.wifi.WIFI_AP_STATE_CHANGED,所以我们只要注册监听这个广播就可以了。

    wifi ap状态值。

     

    public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
    public static int WIFI_AP_STATE_DISABLING = 10;
    public static int WIFI_AP_STATE_DISABLED = 11;
    public static int WIFI_AP_STATE_ENABLING = 12;
    public static int WIFI_AP_STATE_ENABLED = 13;
    public static int WIFI_AP_STATE_FAILED = 14;

    动态注册

     

    public static final String WIFI_AP_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED";
    //注册广播接收者
    IntentFilter filter = new IntentFilter();
    filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
    context.registerReceiver(mWifiStateBroadcastReceiver, filter);

    广播接收者

    通过监听wifiap状态的变化,发送消息给相关activity

     

    //监听wifi热点状态变化
    private BroadcastReceiver mWifiStateBroadcastReceiver = new BroadcastReceiver() {			
    	@Override
            public void onReceive(Context context, Intent intent) {
    	if(DEBUG)Log.i(TAG,"WifiAPUtils onReceive: "+intent.getAction());
    	if(WIFI_AP_STATE_CHANGED_ACTION.equals(intent.getAction())) {
    		    int cstate = intent.getIntExtra(EXTRA_WIFI_AP_STATE, -1);
    		    if(cstate == WIFI_AP_STATE_ENABLED) {
    		    	if(mHandler != null){
    		    		mHandler.sendEmptyMessage(MESSAGE_AP_STATE_ENABLED);			    
    		    	}
    		    }if(cstate == WIFI_AP_STATE_DISABLED  || cstate == WIFI_AP_STATE_FAILED) {
    			if(mHandler != null)
    			    mHandler.sendEmptyMessage(MESSAGE_AP_STATE_FAILED);
    		    }
    		}
    	 }
    };

     

    3 遗留问题

     

     

    在配置wificonfiguration的时候有过属性是hiddenSSID,这个是设置wifi热点AP是否隐藏的,

    但是设置wcfg.hiddenSSID = true或false并没有发现有什么不同,按理说设置为true,ssid隐藏应该搜索不到这个热点,

    但是都可以搜索到。还请知道的可以留言指教,十分感谢。

     

    之前有朋友说5.0系统的开启热点有问题,我这里没有5.0的手机,使用华为p9Android6.0手机测试确实开启不了热点,需要添加write_settings,添加上此权限就可以成功开启了。


    apk测试 低版本下载:链接: https://pan.baidu.com/s/1dzK3rEiwlaD0QrpWe-Vrgg 提取码: 1qpr

    apk测试 8.0下载:链接:https://pan.baidu.com/s/14mQqiaaz5ik0vht8MSYDpg 提取码:dwat 

    DEMO下载

     

    展开全文
  • Android9.0Wifi热点开启流程梳理

    千次阅读 2020-06-27 14:50:53
    Android9.0中对热点做了较大改动,将热点很大程度从Wifi中剥离出来了。 下面我们看一下热点是怎么开启的。 首先是在WifiTetherSettings中,调用startTether()函数,可以看到startTether函数中主要是调用了...

    如果你也是年轻的程序员,关注我一起学习探讨

    在这里插入图片描述
    Android9.0中对热点做了较大改动,将热点很大程度从Wifi中剥离出来了。
    下面我们看一下热点是怎么开启的。

    首先是在WifiTetherSettings中,调用startTether()函数,可以看到startTether函数中主要是调用了WifiTetherSwitchBarController.java中的startTether()函数。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSettings.java#174

        private void startTether() {
              mRestartWifiApAfterConfigChange = false;
              mSwitchBarController.startTether();
        }
    

    然后我们看WifiTetherSwitchBarController里的startTether函数,WifiTetherSwitchBarController是用来控制开关栏切换的,可以看到他调用了ConnectivityManager的startTethering函数。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java#107

        void startTether() {
            mSwitchBar.setEnabled(false);
            mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
                    mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
        }
    

    然后在这里调用了ConnectivityService的startTethering函数。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/net/ConnectivityManager.java#2261

        public void startTethering(int type, boolean showProvisioningUi,
                final OnStartTetheringCallback callback, Handler handler) {
            try {
                String pkgName = mContext.getOpPackageName();
                Log.i(TAG, "startTethering caller:" + pkgName);
                mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName);
            } catch (RemoteException e) {
                Log.e(TAG, "Exception trying to start tethering.", e);
                wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null);
            }
        }
    

    在ConnectivityService中,会跳到Tethering.java的startTethering函数。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/ConnectivityService.java#3232

        public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
                String callerPkg) {
            ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
            if (!isTetheringSupported()) {
                receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
                return;
            }
            mTethering.startTethering(type, receiver, showProvisioningUi);
        }
    

    在Tethering.java中,函数的调用顺序如下:startTethering—>enableTetheringInternal—>setWifiTethering。在setWifiTethering中,调用了WifiManager的startSoftAp函数。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/connectivity/Tethering.java#368

    368    public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
            if (!isTetherProvisioningRequired()) {
                enableTetheringInternal(type, true, receiver);
                return;
            }
    
            if (showProvisioningUi) {
                runUiTetherProvisioningAndEnable(type, receiver);
            } else {
                runSilentTetherProvisioningAndEnable(type, receiver);
            }
        }
    
        private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
            boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
            int result;
            switch (type) {
                case TETHERING_WIFI:
                    result = setWifiTethering(enable);
                    if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
                        scheduleProvisioningRechecks(type);
                    }
                    sendTetherResult(receiver, result);
                    break;
    
        private int setWifiTethering(final boolean enable) {
            int rval = TETHER_ERROR_MASTER_ERROR;
            final long ident = Binder.clearCallingIdentity();
            try {
                synchronized (mPublicSync) {
                    mWifiTetherRequested = enable;
                    final WifiManager mgr = getWifiManager();
                    if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
                        (!enable && mgr.stopSoftAp())) {
                        rval = TETHER_ERROR_NO_ERROR;
                    }
                }
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
            return rval;
        }
    

    在这里调用了WifiServiceImpl.java的startSoftAp函数。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/frameworks/base/wifi/java/android/net/wifi/WifiManager.java#1909

        public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
            try {
                return mService.startSoftAp(wifiConfig);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    在这里调用了startSoftApInternal函数,然后向WifiController的状态机发送了CMD_SET_AP消息。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java#1004

        public boolean startSoftAp(WifiConfiguration wifiConfig) {
            // NETWORK_STACK is a signature only permission.
            enforceNetworkStackPermission();
    
            mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
    
            synchronized (mLocalOnlyHotspotRequests) {
                // If a tethering request comes in while we have LOHS running (or requested), call stop
                // for softap mode and restart softap with the tethering config.
                if (!mLocalOnlyHotspotRequests.isEmpty()) {
                    stopSoftApInternal();
                }
                return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
            }
        }
    
        private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
            mLog.trace("startSoftApInternal uid=% mode=%")
                    .c(Binder.getCallingUid()).c(mode).flush();
    
            // null wifiConfig is a meaningful input for CMD_SET_AP
            if (wifiConfig == null || WifiApConfigStore.validateApWifiConfiguration(wifiConfig)) {
                SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
                mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
                return true;
            }
            Slog.e(TAG, "Invalid WifiConfiguration");
            return false;
        }
    

    在这里,处理结果是调用WifiStateMachinePrime的enterSoftAPMode方法。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java#593

        class DefaultState extends State {
                    case CMD_SET_AP:
                        // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
    
                        // first make sure we aren't in airplane mode
                        if (mSettingsStore.isAirplaneModeOn()) {
                            log("drop softap requests when in airplane mode");
                            break;
                        }
                        if (msg.arg1 == 1) {
                            SoftApModeConfiguration config = (SoftApModeConfiguration) msg.obj;
                           mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
                        } else {
                            mWifiStateMachinePrime.stopSoftAPMode();
                        }
                        break;
    

    在WifiStateMachinePrime中,创建了SoftApManager对象,并且调用了start方法。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachinePrime.java#549

        public void enterSoftAPMode(@NonNull SoftApModeConfiguration wifiConfig) {
            mHandler.post(() -> {
                startSoftAp(wifiConfig);
            });
        }
    
        private void startSoftAp(SoftApModeConfiguration softapConfig) {
            Log.d(TAG, "Starting SoftApModeManager");
    
            WifiConfiguration config = softapConfig.getWifiConfiguration();
            if (config != null && config.SSID != null) {
                Log.d(TAG, "Passing config to SoftApManager! " + config);
            } else {
                config = null;
            }
    
            SoftApCallbackImpl callback = new SoftApCallbackImpl();
            ActiveModeManager manager = mWifiInjector.makeSoftApManager(callback, softapConfig);
            callback.setActiveModeManager(manager);
            manager.start();
            mActiveModeManagers.add(manager);
            updateBatteryStatsWifiState(true);
        }
    

    在这里,StateMachine发送了消息CMD_START,然后由IdleState 处理,这里主要的处理结果就是调用startSoftAp方法。在startSoftAp里,调用了WifiNative.java的startSoftAp方法。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/SoftApManager.java#142

        public void start() {
            mStateMachine.sendMessage(SoftApStateMachine.CMD_START, mApConfig);
        }
    
            private class IdleState extends State {
                public boolean processMessage(Message message) {
                    switch (message.what) {
                        case CMD_START:
                            mApInterfaceName = mWifiNative.setupInterfaceForSoftApMode(
                                    mWifiNativeInterfaceCallback);
                            if (TextUtils.isEmpty(mApInterfaceName)) {
                                Log.e(TAG, "setup failure when creating ap interface.");
                                updateApState(WifiManager.WIFI_AP_STATE_FAILED,
                                        WifiManager.WIFI_AP_STATE_DISABLED,
                                        WifiManager.SAP_START_FAILURE_GENERAL);
                                mWifiMetrics.incrementSoftApStartResult(
                                        false, WifiManager.SAP_START_FAILURE_GENERAL);
                                break;
                            }
                            updateApState(WifiManager.WIFI_AP_STATE_ENABLING,
                                    WifiManager.WIFI_AP_STATE_DISABLED, 0);
                            int result = startSoftAp((WifiConfiguration) message.obj);
                            if (result != SUCCESS) {
                                int failureReason = WifiManager.SAP_START_FAILURE_GENERAL;
                                if (result == ERROR_NO_CHANNEL) {
                                    failureReason = WifiManager.SAP_START_FAILURE_NO_CHANNEL;
                                }
                                updateApState(WifiManager.WIFI_AP_STATE_FAILED,
                                              WifiManager.WIFI_AP_STATE_ENABLING,
                                              failureReason);
                                stopSoftAp();
                                mWifiMetrics.incrementSoftApStartResult(false, failureReason);
                                break;
                            }
                            transitionTo(mStartedState);
                            break;
    
        private int startSoftAp(WifiConfiguration config) {
            if (config == null || config.SSID == null) {
                Log.e(TAG, "Unable to start soft AP without valid configuration");
                return ERROR_GENERIC;
            }
    
            // Make a copy of configuration for updating AP band and channel.
            WifiConfiguration localConfig = new WifiConfiguration(config);
    
            int result = ApConfigUtil.updateApChannelConfig(
                    mWifiNative, mCountryCode,
                    mWifiApConfigStore.getAllowed2GChannel(), localConfig);
    
            if (result != SUCCESS) {
                Log.e(TAG, "Failed to update AP band and channel");
                return result;
            }
    
            // Setup country code if it is provided.
            if (mCountryCode != null) {
                // Country code is mandatory for 5GHz band, return an error if failed to set
                // country code when AP is configured for 5GHz band.
                if (!mWifiNative.setCountryCodeHal(
                        mApInterfaceName, mCountryCode.toUpperCase(Locale.ROOT))
                        && config.apBand == WifiConfiguration.AP_BAND_5GHZ) {
                    Log.e(TAG, "Failed to set country code, required for setting up "
                            + "soft ap in 5GHz");
                    return ERROR_GENERIC;
                }
            }
            if (localConfig.hiddenSSID) {
                Log.d(TAG, "SoftAP is a hidden network");
            }
            if (!mWifiNative.startSoftAp(mApInterfaceName, localConfig, mSoftApListener)) {
                Log.e(TAG, "Soft AP start failed");
                return ERROR_GENERIC;
            }
            Log.d(TAG, "Soft AP is started");
    
            return SUCCESS;
        }
    

    在这里,主要是调用WificondControl.java的startHostapd方法。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java#1250

        public boolean startSoftAp(
                @NonNull String ifaceName, WifiConfiguration config, SoftApListener listener) {
            if (!mWificondControl.startHostapd(ifaceName, listener)) {
                Log.e(TAG, "Failed to start hostapd");
                mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
                return false;
            }
            if (!waitForHostapdConnection()) {
                Log.e(TAG, "Failed to establish connection to hostapd");
                mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
                return false;
            }
            if (!mHostapdHal.registerDeathHandler(new HostapdDeathHandlerInternal())) {
                Log.e(TAG, "Failed to register hostapd death handler");
                mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
                return false;
            }
            if (!mHostapdHal.addAccessPoint(ifaceName, config)) {
                Log.e(TAG, "Failed to add acccess point");
                mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
                return false;
            }
            return true;
        }
    

    在这里可以看到创建了IApInterface 对象,然后调用了他的startHostapd方法。而IApInterface 是由ap_interface_impl.cpp实现的。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java#787

        public boolean startHostapd(@NonNull String ifaceName,
                                   SoftApListener listener) {
            IApInterface iface = getApInterface(ifaceName);
            if (iface == null) {
                Log.e(TAG, "No valid ap interface handler");
                return false;
            }
            try {
                IApInterfaceEventCallback  callback = new ApInterfaceEventCallback(listener);
                mApInterfaceListeners.put(ifaceName, callback);
                boolean success = iface.startHostapd(callback);
                if (!success) {
                    Log.e(TAG, "Failed to start hostapd.");
                    return false;
                }
            } catch (RemoteException e) {
                Log.e(TAG, "Exception in starting soft AP: " + e);
                return false;
            }
            return true;
        }
    

    在这里又调用了hostapd_manager的StartHostapd函数。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/system/connectivity/wificond/ap_interface_impl.cpp#86

    bool ApInterfaceImpl::StartHostapd() {
      return hostapd_manager_->StartHostapd();
    }
    

    然后在hostapd_manager.cpp里调用了StartHostapd方法。
    源码路径:
    http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/libwifi_system/hostapd_manager.cpp#26

    bool HostapdManager::StartHostapd() {
      if (property_set("ctl.start", kHostapdServiceName) != 0) {
        LOG(ERROR) << "Failed to start SoftAP";
        return false;
          LOG(DEBUG) << "SoftAP started successfully";
      return true;
    }
    

    再往后就是底层C的代码了,不是特别看得懂。然后返回success的话,热点就成功打开了,状态也变为started。

    展开全文
  • Wifi热点

    2019-01-11 16:36:27
    最近在开发手机短距离传输有关的产品,由于蓝牙传输速率有限,采用的是wifi热点的方式。 1.WIFI热点的操作需要以下权限: &lt;uses-permission android:name="android.permission.ACCESS_WIFI_STATE&...
  • 现在的无线热点设备大都支持2.4G和5G两个频段,但目前支持5G的终端设备还很少,故无线热点设备还是更多的被使用2.4G的频段,而2.4G的频段最多只支持14个信道(且根据不同的国家而支持的又不一样),根据文章...
  • Mac如何共享wifi热点

    万次阅读 2019-08-09 19:02:33
    ... ... 四、设置完成后,勾选“互联网共享”,确定启动 ...Mac共享热点支持有线连接、蓝牙连接的网络进行共享,如果你的mac本身是通过wifi来连接上网的,那就不能用这个mac做wifi热点了,因为wifi端口已...
  • Android手机通过wifi进行数据传输(一)

    万次阅读 热门讨论 2016-06-21 15:20:00
    在Android手机上可以通过在收方开启一个wifi热点,然后再发送方连接这个wifi热点。这样他们就在一个局域网,然后通过socket进行通信。 本文的demo程序写得比较简单。 对于收方,首先点击“创建wifi热点”按钮,开启...
  • 笔记本能连上手机热点,但不能连接WIFI,说明不是WIFI的问题,是电脑自身问题 进入cmd里面输入 ipconfig/all 命令,出现IP地址始终为:169.154(或者其他)开头,然后去设置IP地址处发现设置好的IP地址不变,但跟...
  • Android WiFi开发教程(一)——WiFi热点的创建与关闭

    万次阅读 多人点赞 2019-06-14 16:13:18
    相对于BlueTooth,WiFi是当今使用最广的一种无线网络传输技术, 几乎所有智能手机、平板电脑和笔记本电脑都支持Wi-Fi上网。...功能主要有创建WiFi热点,关闭WiFi热点,搜索WiFi,连接WiFi,数据通讯。源码会在教
  • 关于win10笔记本能连上热点不能连接WIFI的问题

    万次阅读 热门讨论 2018-10-18 16:36:29
    今天突然早上上班发现自己的电脑不能连网,然后用手机却能连接上,说明不是WIFI的问题,然后用手机开热点电脑能连接上,说明是电脑自身问题,网上查找了很多方法都一一尝试了都没有得到解决,最后看到一篇帖子跟我的...
  • Win10 开启移动热点 WiFi 的简单方法

    万次阅读 2017-08-14 17:38:57
    Win 10 开启移动热点 WiFi 的方法很简单,只需使用鼠标点几下就好。
  • 问题描述:本人用的是Win10 系统,平时在学校一直用电脑连接自己的手机热点,回到家后突然发现电脑连接自家的Wifi上网后打开浏览器显示无法连接到该网络,但是qq又能正常登陆并且接收同学发来的消息。检查浏览器一切...
  • win7笔记本电脑设置WiFi热点

    千次阅读 2019-04-15 08:09:50
    一般情况下,我们是利用路由器设置WiFi热点,但是如果没有路由器,而有网线,我们可以利用笔记本电脑来设置WiFi热点,这里介绍如何通过笔记本电脑连接网线设置WiFi热点。笔记本电脑设置WiFi热点,需要明确两点: 1...
  • 在没有路由器,自己电脑又不想下载wifi软件的情况下,可以使用本机网络开启wifi热点(CMD命令)。win+R 运行cmd 进入到控制台第一步输入:netsh wlan set hostednetwork mode=allow ssid=WIFI_NAME key=WIFI_...
  • 这个百度经验还是不错的:https://jingyan.baidu.com/article/cb5d6105ebab87005d2fe06a.html 根据这个链接,可以配置。
  • 开启Wifi热点时的互斥关系

    千次阅读 2015-09-22 11:40:44
    Wifi和热点不能同时开启:因此在开启Wifi时需要先关闭热点,... * Wifi热点开关. Wifi和热点不能同时打开,所以打开Wifi的时候需要关闭热点 * * @author jiangping.li * @return * @since MT 1.0 */ public bo
  • Android8.0 WiFi热点适配

    万次阅读 热门讨论 2017-11-27 21:55:07
    在Android8.0上用以前的方式调试WiFi热点的时候发现无法正常开启热点,于是查了下,发现之前的热点打开接口已经废弃。原先的接口WifiManager.java中setWifiApEnabled方法用来打开WiFi热点已经用不了了。网上查是从...
  • Android 获取便携式热点开关状态、热点开启与关闭

    万次阅读 热门讨论 2019-05-08 15:00:03
    第一个功能,在百度基本找不到,最后我是在google找到的,getWifiApState()这个方法我也不懂是什意思,麻烦知道的指点一下,谢谢。第一次写博,不知道怎样更改代码格式,看的不爽还请见谅。 原创博客,装载注明地址...
1 2 3 4 5 ... 20
收藏数 21,016
精华内容 8,406
关键字:

wifi热点