Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 47c6c860 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add Instant hotspot preference" into main

parents e7377fc7 63321a1a
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -2179,6 +2179,13 @@
    <!-- The footer message for Wi-Fi hotspot security settings [CHAR LIMIT=NONE] -->
    <string name="wifi_hotspot_security_footer">Security settings may change if you change the hotspot’s frequency</string>
    <!-- Title for the instant hotspot state [CHAR LIMIT=NONE]-->
    <string name="wifi_hotspot_instant_title">Instant hotspot</string>
    <!-- Summary text when instant hotspot is turned on -->
    <string name="wifi_hotspot_instant_summary_on">On</string>
    <!-- Summary text when instant hotspot is turned off -->
    <string name="wifi_hotspot_instant_summary_off">Off</string>
    <!-- Summary text when turning hotspot on -->
    <string name="wifi_tether_starting">Turning hotspot on\u2026</string>
    <!-- Summary text when turning hotspot off -->
+6 −0
Original line number Diff line number Diff line
@@ -59,4 +59,10 @@
        android:summary="@string/summary_placeholder"
        android:fragment="com.android.settings.wifi.tether.WifiHotspotSpeedSettings"
        settings:isPreferenceVisible="@bool/config_show_wifi_hotspot_speed"/>

    <Preference
        android:key="wifi_hotspot_instant"
        android:title="@string/wifi_hotspot_instant_title"
        android:summary="@string/summary_placeholder"
        settings:isPreferenceVisible="false"/>
</PreferenceScreen>
+13 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner;

import com.android.settings.wifi.repository.SharedConnectivityRepository;
import com.android.settings.wifi.repository.WifiHotspotRepository;
import com.android.settings.wifi.tether.WifiHotspotSecurityViewModel;
import com.android.settings.wifi.tether.WifiHotspotSpeedViewModel;
@@ -44,6 +45,7 @@ public class WifiFeatureProvider {
    private TetheringManager mTetheringManager;
    private WifiVerboseLogging mWifiVerboseLogging;
    private WifiHotspotRepository mWifiHotspotRepository;
    private SharedConnectivityRepository mSharedConnectivityRepository;

    public WifiFeatureProvider(@NonNull Context appContext) {
        mAppContext = appContext;
@@ -92,6 +94,17 @@ public class WifiFeatureProvider {
        return mWifiHotspotRepository;
    }

    /**
     * Gets SharedConnectivityRepository
     */
    public SharedConnectivityRepository getSharedConnectivityRepository() {
        if (mSharedConnectivityRepository == null) {
            mSharedConnectivityRepository = new SharedConnectivityRepository(mAppContext);
            verboseLog(TAG, "getSharedConnectivityRepository():" + mSharedConnectivityRepository);
        }
        return mSharedConnectivityRepository;
    }

    /**
     * Gets WifiTetherViewModel
     */
+184 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settings.wifi.repository;

import android.app.PendingIntent;
import android.content.Context;
import android.net.wifi.sharedconnectivity.app.HotspotNetwork;
import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus;
import android.net.wifi.sharedconnectivity.app.KnownNetwork;
import android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus;
import android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback;
import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager;
import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState;
import android.os.HandlerThread;
import android.provider.DeviceConfig;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import com.android.settings.overlay.FeatureFactory;

import java.util.List;
import java.util.concurrent.Executor;

/**
 * Shared Connectivity Repository for {@link SharedConnectivityManager}
 */
public class SharedConnectivityRepository {
    private static final String TAG = "SharedConnectivityRepository";
    private static final String DEVICE_CONFIG_NAMESPACE = "wifi";
    private static final String DEVICE_CONFIG_KEY = "shared_connectivity_enabled";

    private Context mAppContext;
    private SharedConnectivityManager mManager;
    private ClientCallback mClientCallback = new ClientCallback();
    private HandlerThread mWorkerThread = new HandlerThread(TAG);
    private Executor mWorkerExecutor = cmd -> mWorkerThread.getThreadHandler().post(cmd);
    private Runnable mLaunchSettingsRunnable = () -> handleLaunchSettings();
    @VisibleForTesting
    MutableLiveData<SharedConnectivitySettingsState> mSettingsState = new MutableLiveData<>();

    public SharedConnectivityRepository(@NonNull Context appContext) {
        this(appContext,
                DeviceConfig.getBoolean(DEVICE_CONFIG_NAMESPACE, DEVICE_CONFIG_KEY, false));
    }

    @VisibleForTesting
    SharedConnectivityRepository(@NonNull Context appContext, boolean isConfigEnabled) {
        mAppContext = appContext;
        if (!isConfigEnabled) {
            return;
        }
        mManager = mAppContext.getSystemService(SharedConnectivityManager.class);
        if (mManager == null) {
            Log.w(TAG, "Failed to get SharedConnectivityManager");
            return;
        }
        mWorkerThread.start();
        mManager.registerCallback(mWorkerExecutor, mClientCallback);
    }

    /**
     * Return whether Wi-Fi Shared Connectivity service is available or not.
     *
     * @return {@code true} if Wi-Fi Shared Connectivity service is available
     */
    public boolean isServiceAvailable() {
        return mManager != null;
    }

    /**
     * Gets SharedConnectivitySettingsState LiveData
     */
    public LiveData<SharedConnectivitySettingsState> getSettingsState() {
        return mSettingsState;
    }

    /**
     * Launch Instant Hotspot Settings
     */
    public void launchSettings() {
        mWorkerExecutor.execute(mLaunchSettingsRunnable);
    }

    @WorkerThread
    @VisibleForTesting
    void handleLaunchSettings() {
        if (mManager == null) {
            return;
        }
        SharedConnectivitySettingsState state = mManager.getSettingsState();
        log("handleLaunchSettings(), state:" + state);
        if (state == null) {
            Log.e(TAG, "No SettingsState to launch Instant Hotspot settings");
            return;
        }
        PendingIntent intent = state.getInstantTetherSettingsPendingIntent();
        if (intent == null) {
            Log.e(TAG, "No PendingIntent to launch Instant Hotspot settings");
            return;
        }
        sendSettingsIntent(intent);
    }

    @WorkerThread
    @VisibleForTesting
    void sendSettingsIntent(@NonNull PendingIntent intent) {
        try {
            log("sendSettingsIntent(), sent intent:" + intent);
            intent.send();
        } catch (PendingIntent.CanceledException e) {
            Log.e(TAG, "Failed to launch Instant Hotspot settings", e);
        }
    }

    @WorkerThread
    class ClientCallback implements SharedConnectivityClientCallback {

        @Override
        public void onHotspotNetworkConnectionStatusChanged(HotspotNetworkConnectionStatus status) {
            log("onHotspotNetworkConnectionStatusChanged(), status:" + status);
        }

        @Override
        public void onHotspotNetworksUpdated(List<HotspotNetwork> networks) {
            log("onHotspotNetworksUpdated(), networks:" + networks);
        }

        @Override
        public void onKnownNetworkConnectionStatusChanged(KnownNetworkConnectionStatus status) {
            log("onKnownNetworkConnectionStatusChanged(), status:" + status);
        }

        @Override
        public void onKnownNetworksUpdated(List<KnownNetwork> networks) {
            log("onKnownNetworksUpdated(), networks:" + networks);
        }

        @Override
        public void onRegisterCallbackFailed(Exception e) {
            Log.e(TAG, "onRegisterCallbackFailed(), e:" + e);
        }

        @Override
        public void onServiceConnected() {
            SharedConnectivitySettingsState state = mManager.getSettingsState();
            Log.d(TAG, "onServiceConnected(), Manager#getSettingsState:" + state);
            mSettingsState.postValue(state);
        }

        @Override
        public void onServiceDisconnected() {
            log("onServiceDisconnected()");
        }

        @Override
        public void onSharedConnectivitySettingsChanged(SharedConnectivitySettingsState state) {
            Log.d(TAG, "onSharedConnectivitySettingsChanged(), state:" + state);
            mSettingsState.postValue(state);
        }
    }

    private void log(String msg) {
        FeatureFactory.getFeatureFactory().getWifiFeatureProvider().verboseLog(TAG, msg);
    }
}
+33 −0
Original line number Diff line number Diff line
@@ -76,6 +76,8 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
    static final String KEY_WIFI_HOTSPOT_SECURITY = "wifi_hotspot_security";
    @VisibleForTesting
    static final String KEY_WIFI_HOTSPOT_SPEED = "wifi_hotspot_speed";
    @VisibleForTesting
    static final String KEY_INSTANT_HOTSPOT = "wifi_hotspot_instant";

    @VisibleForTesting
    SettingsMainSwitchBar mMainSwitchBar;
@@ -103,6 +105,8 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
    Preference mWifiHotspotSecurity;
    @VisibleForTesting
    Preference mWifiHotspotSpeed;
    @VisibleForTesting
    Preference mInstantHotspot;

    static {
        TETHER_STATE_CHANGE_FILTER = new IntentFilter(WIFI_AP_STATE_CHANGED_ACTION);
@@ -148,6 +152,7 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
                .getWifiTetherViewModel(this);
        if (mWifiTetherViewModel != null) {
            setupSpeedFeature(mWifiTetherViewModel.isSpeedFeatureAvailable());
            setupInstantHotspot(mWifiTetherViewModel.isInstantHotspotFeatureAvailable());
            mWifiTetherViewModel.getRestarting().observe(this, this::onRestartingChanged);
        }
    }
@@ -167,6 +172,24 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
        }
    }

    @VisibleForTesting
    void setupInstantHotspot(boolean isFeatureAvailable) {
        if (!isFeatureAvailable) {
            return;
        }
        mInstantHotspot = findPreference(KEY_INSTANT_HOTSPOT);
        if (mInstantHotspot == null) {
            Log.e(TAG, "Failed to find Instant Hotspot preference:" + KEY_INSTANT_HOTSPOT);
            return;
        }
        mWifiTetherViewModel.getInstantHotspotSummary()
                .observe(this, this::onInstantHotspotChanged);
        mInstantHotspot.setOnPreferenceClickListener(p -> {
            mWifiTetherViewModel.launchInstantHotspotSettings();
            return true;
        });
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
@@ -279,6 +302,16 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
        setLoading(restarting, false);
    }

    @VisibleForTesting
    void onInstantHotspotChanged(String summary) {
        if (summary == null) {
            mInstantHotspot.setVisible(false);
            return;
        }
        mInstantHotspot.setVisible(true);
        mInstantHotspot.setSummary(summary);
    }

    @VisibleForTesting
    SoftApConfiguration buildNewConfig() {
        SoftApConfiguration currentConfig = mWifiTetherViewModel.getSoftApConfiguration();
Loading