1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.wifi.repository; 18 19 import android.app.PendingIntent; 20 import android.content.Context; 21 import android.net.wifi.sharedconnectivity.app.HotspotNetwork; 22 import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus; 23 import android.net.wifi.sharedconnectivity.app.KnownNetwork; 24 import android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus; 25 import android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback; 26 import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager; 27 import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState; 28 import android.os.HandlerThread; 29 import android.provider.DeviceConfig; 30 import android.util.Log; 31 32 import androidx.annotation.NonNull; 33 import androidx.annotation.VisibleForTesting; 34 import androidx.annotation.WorkerThread; 35 import androidx.lifecycle.LiveData; 36 import androidx.lifecycle.MutableLiveData; 37 38 import com.android.settings.overlay.FeatureFactory; 39 40 import java.util.List; 41 import java.util.concurrent.Executor; 42 43 /** 44 * Shared Connectivity Repository for {@link SharedConnectivityManager} 45 */ 46 public class SharedConnectivityRepository { 47 private static final String TAG = "SharedConnectivityRepository"; 48 private static final String DEVICE_CONFIG_NAMESPACE = "wifi"; 49 private static final String DEVICE_CONFIG_KEY = "shared_connectivity_enabled"; 50 51 private Context mAppContext; 52 private SharedConnectivityManager mManager; 53 private ClientCallback mClientCallback = new ClientCallback(); 54 private HandlerThread mWorkerThread = new HandlerThread(TAG); 55 private Executor mWorkerExecutor = cmd -> mWorkerThread.getThreadHandler().post(cmd); 56 private Runnable mLaunchSettingsRunnable = () -> handleLaunchSettings(); 57 @VisibleForTesting 58 MutableLiveData<SharedConnectivitySettingsState> mSettingsState = new MutableLiveData<>(); 59 SharedConnectivityRepository(@onNull Context appContext)60 public SharedConnectivityRepository(@NonNull Context appContext) { 61 this(appContext, isDeviceConfigEnabled()); 62 } 63 64 @VisibleForTesting SharedConnectivityRepository(@onNull Context appContext, boolean isConfigEnabled)65 SharedConnectivityRepository(@NonNull Context appContext, boolean isConfigEnabled) { 66 mAppContext = appContext; 67 if (!isConfigEnabled) { 68 return; 69 } 70 mManager = mAppContext.getSystemService(SharedConnectivityManager.class); 71 if (mManager == null) { 72 Log.w(TAG, "Failed to get SharedConnectivityManager"); 73 return; 74 } 75 mWorkerThread.start(); 76 mManager.registerCallback(mWorkerExecutor, mClientCallback); 77 } 78 79 /** 80 * Return whether Wi-Fi Shared Connectivity service is available or not. 81 * 82 * @return {@code true} if Wi-Fi Shared Connectivity service is available 83 */ isServiceAvailable()84 public boolean isServiceAvailable() { 85 return mManager != null; 86 } 87 88 /** 89 * Gets SharedConnectivitySettingsState LiveData 90 */ getSettingsState()91 public LiveData<SharedConnectivitySettingsState> getSettingsState() { 92 return mSettingsState; 93 } 94 95 /** 96 * Launch Instant Hotspot Settings 97 */ launchSettings()98 public void launchSettings() { 99 mWorkerExecutor.execute(mLaunchSettingsRunnable); 100 } 101 102 @WorkerThread 103 @VisibleForTesting handleLaunchSettings()104 void handleLaunchSettings() { 105 if (mManager == null) { 106 return; 107 } 108 SharedConnectivitySettingsState state = mManager.getSettingsState(); 109 log("handleLaunchSettings(), state:" + state); 110 if (state == null) { 111 Log.e(TAG, "No SettingsState to launch Instant Hotspot settings"); 112 return; 113 } 114 PendingIntent intent = state.getInstantTetherSettingsPendingIntent(); 115 if (intent == null) { 116 Log.e(TAG, "No PendingIntent to launch Instant Hotspot settings"); 117 return; 118 } 119 sendSettingsIntent(intent); 120 } 121 122 @WorkerThread 123 @VisibleForTesting sendSettingsIntent(@onNull PendingIntent intent)124 void sendSettingsIntent(@NonNull PendingIntent intent) { 125 try { 126 log("sendSettingsIntent(), sent intent:" + intent); 127 intent.send(); 128 } catch (PendingIntent.CanceledException e) { 129 Log.e(TAG, "Failed to launch Instant Hotspot settings", e); 130 } 131 } 132 133 @WorkerThread 134 class ClientCallback implements SharedConnectivityClientCallback { 135 136 @Override onHotspotNetworkConnectionStatusChanged(HotspotNetworkConnectionStatus status)137 public void onHotspotNetworkConnectionStatusChanged(HotspotNetworkConnectionStatus status) { 138 log("onHotspotNetworkConnectionStatusChanged(), status:" + status); 139 } 140 141 @Override onHotspotNetworksUpdated(List<HotspotNetwork> networks)142 public void onHotspotNetworksUpdated(List<HotspotNetwork> networks) { 143 log("onHotspotNetworksUpdated(), networks:" + networks); 144 } 145 146 @Override onKnownNetworkConnectionStatusChanged(KnownNetworkConnectionStatus status)147 public void onKnownNetworkConnectionStatusChanged(KnownNetworkConnectionStatus status) { 148 log("onKnownNetworkConnectionStatusChanged(), status:" + status); 149 } 150 151 @Override onKnownNetworksUpdated(List<KnownNetwork> networks)152 public void onKnownNetworksUpdated(List<KnownNetwork> networks) { 153 log("onKnownNetworksUpdated(), networks:" + networks); 154 } 155 156 @Override onRegisterCallbackFailed(Exception e)157 public void onRegisterCallbackFailed(Exception e) { 158 Log.e(TAG, "onRegisterCallbackFailed(), e:" + e); 159 } 160 161 @Override onServiceConnected()162 public void onServiceConnected() { 163 SharedConnectivitySettingsState state = mManager.getSettingsState(); 164 Log.d(TAG, "onServiceConnected(), Manager#getSettingsState:" + state); 165 mSettingsState.postValue(state); 166 } 167 168 @Override onServiceDisconnected()169 public void onServiceDisconnected() { 170 log("onServiceDisconnected()"); 171 } 172 173 @Override onSharedConnectivitySettingsChanged(SharedConnectivitySettingsState state)174 public void onSharedConnectivitySettingsChanged(SharedConnectivitySettingsState state) { 175 Log.d(TAG, "onSharedConnectivitySettingsChanged(), state:" + state); 176 mSettingsState.postValue(state); 177 } 178 } 179 log(String msg)180 private void log(String msg) { 181 FeatureFactory.getFactory(mAppContext).getWifiFeatureProvider().verboseLog(TAG, msg); 182 } 183 184 /** 185 * Returns true if Shared Connectivity feature is enabled. 186 */ isDeviceConfigEnabled()187 public static boolean isDeviceConfigEnabled() { 188 return DeviceConfig.getBoolean(DEVICE_CONFIG_NAMESPACE, DEVICE_CONFIG_KEY, false); 189 } 190 } 191