1 /* 2 * Copyright (C) 2019 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 package com.android.settings.wifi.details2; 17 18 import static com.android.settings.wifi.WifiSettings.WIFI_DIALOG_ID; 19 20 import android.app.Dialog; 21 import android.app.admin.DevicePolicyManager; 22 import android.app.settings.SettingsEnums; 23 import android.content.Context; 24 import android.net.ConnectivityManager; 25 import android.net.NetworkScoreManager; 26 import android.net.wifi.WifiManager; 27 import android.os.Handler; 28 import android.os.HandlerThread; 29 import android.os.Looper; 30 import android.os.Process; 31 import android.os.SimpleClock; 32 import android.os.SystemClock; 33 import android.os.UserHandle; 34 import android.os.UserManager; 35 import android.view.Menu; 36 import android.view.MenuInflater; 37 import android.view.MenuItem; 38 39 import androidx.annotation.VisibleForTesting; 40 import androidx.preference.PreferenceScreen; 41 42 import com.android.settings.R; 43 import com.android.settings.Utils; 44 import com.android.settings.dashboard.DashboardFragment; 45 import com.android.settings.wifi.WifiConfigUiBase2; 46 import com.android.settings.wifi.WifiDialog2; 47 import com.android.settingslib.RestrictedLockUtils; 48 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 49 import com.android.settingslib.RestrictedLockUtilsInternal; 50 import com.android.settingslib.core.AbstractPreferenceController; 51 import com.android.wifitrackerlib.NetworkDetailsTracker; 52 import com.android.wifitrackerlib.WifiEntry; 53 54 import java.time.Clock; 55 import java.time.ZoneOffset; 56 import java.util.ArrayList; 57 import java.util.List; 58 59 /** 60 * Detail page for the currently connected wifi network. 61 * 62 * <p>The key of {@link WifiEntry} should be saved to the intent Extras when launching this class 63 * in order to properly render this page. 64 */ 65 public class WifiNetworkDetailsFragment2 extends DashboardFragment implements 66 WifiDialog2.WifiDialog2Listener { 67 68 private static final String TAG = "WifiNetworkDetailsFrg2"; 69 70 // Key of a Bundle to save/restore the selected WifiEntry 71 public static final String KEY_CHOSEN_WIFIENTRY_KEY = "key_chosen_wifientry_key"; 72 73 // Max age of tracked WifiEntries 74 private static final long MAX_SCAN_AGE_MILLIS = 15_000; 75 // Interval between initiating SavedNetworkTracker scans 76 private static final long SCAN_INTERVAL_MILLIS = 10_000; 77 78 @VisibleForTesting 79 NetworkDetailsTracker mNetworkDetailsTracker; 80 private HandlerThread mWorkerThread; 81 private WifiDetailPreferenceController2 mWifiDetailPreferenceController2; 82 private List<WifiDialog2.WifiDialog2Listener> mWifiDialogListeners = new ArrayList<>(); 83 @VisibleForTesting 84 List<AbstractPreferenceController> mControllers; 85 86 @Override onDestroy()87 public void onDestroy() { 88 mWorkerThread.quit(); 89 90 super.onDestroy(); 91 } 92 93 @Override getMetricsCategory()94 public int getMetricsCategory() { 95 return SettingsEnums.WIFI_NETWORK_DETAILS; 96 } 97 98 @Override getLogTag()99 protected String getLogTag() { 100 return TAG; 101 } 102 103 @Override getPreferenceScreenResId()104 protected int getPreferenceScreenResId() { 105 return R.xml.wifi_network_details_fragment2; 106 } 107 108 @Override getDialogMetricsCategory(int dialogId)109 public int getDialogMetricsCategory(int dialogId) { 110 if (dialogId == WIFI_DIALOG_ID) { 111 return SettingsEnums.DIALOG_WIFI_AP_EDIT; 112 } 113 return 0; 114 } 115 116 @Override onCreateDialog(int dialogId)117 public Dialog onCreateDialog(int dialogId) { 118 if (getActivity() == null || mWifiDetailPreferenceController2 == null) { 119 return null; 120 } 121 122 final WifiEntry wifiEntry = mNetworkDetailsTracker.getWifiEntry(); 123 return WifiDialog2.createModal(getActivity(), this, wifiEntry, 124 WifiConfigUiBase2.MODE_MODIFY); 125 } 126 127 @Override onCreateOptionsMenu(Menu menu, MenuInflater inflater)128 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 129 if (isEditable()) { 130 MenuItem item = menu.add(0, Menu.FIRST, 0, R.string.wifi_modify); 131 item.setIcon(com.android.internal.R.drawable.ic_mode_edit); 132 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); 133 } 134 super.onCreateOptionsMenu(menu, inflater); 135 } 136 137 @Override onOptionsItemSelected(MenuItem menuItem)138 public boolean onOptionsItemSelected(MenuItem menuItem) { 139 switch (menuItem.getItemId()) { 140 case Menu.FIRST: 141 if (!mWifiDetailPreferenceController2.canModifyNetwork()) { 142 EnforcedAdmin admin = RestrictedLockUtilsInternal.getDeviceOwner(getContext()); 143 if (admin == null) { 144 final DevicePolicyManager dpm = (DevicePolicyManager) 145 getContext().getSystemService(Context.DEVICE_POLICY_SERVICE); 146 final UserManager um = (UserManager) 147 getContext().getSystemService(Context.USER_SERVICE); 148 final int profileOwnerUserId = Utils.getManagedProfileId( 149 um, UserHandle.myUserId()); 150 if (profileOwnerUserId != UserHandle.USER_NULL) { 151 admin = new EnforcedAdmin(dpm.getProfileOwnerAsUser(profileOwnerUserId), 152 null, UserHandle.of(profileOwnerUserId)); 153 } 154 } 155 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), admin); 156 } else { 157 showDialog(WIFI_DIALOG_ID); 158 } 159 return true; 160 default: 161 return super.onOptionsItemSelected(menuItem); 162 } 163 } 164 165 @Override createPreferenceControllers(Context context)166 protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { 167 mControllers = new ArrayList<>(); 168 final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class); 169 setupNetworksDetailTracker(); 170 final WifiEntry wifiEntry = mNetworkDetailsTracker.getWifiEntry(); 171 172 final WifiSecondSummaryController2 wifiSecondSummaryController2 = 173 new WifiSecondSummaryController2(context); 174 wifiSecondSummaryController2.setWifiEntry(wifiEntry); 175 mControllers.add(wifiSecondSummaryController2); 176 177 mWifiDetailPreferenceController2 = WifiDetailPreferenceController2.newInstance( 178 wifiEntry, 179 cm, 180 context, 181 this, 182 new Handler(Looper.getMainLooper()), // UI thread. 183 getSettingsLifecycle(), 184 context.getSystemService(WifiManager.class), 185 mMetricsFeatureProvider); 186 mControllers.add(mWifiDetailPreferenceController2); 187 188 final WifiAutoConnectPreferenceController2 wifiAutoConnectPreferenceController2 = 189 new WifiAutoConnectPreferenceController2(context); 190 wifiAutoConnectPreferenceController2.setWifiEntry(wifiEntry); 191 mControllers.add(wifiAutoConnectPreferenceController2); 192 193 final AddDevicePreferenceController2 addDevicePreferenceController2 = 194 new AddDevicePreferenceController2(context); 195 addDevicePreferenceController2.setWifiEntry(wifiEntry); 196 mControllers.add(addDevicePreferenceController2); 197 198 final WifiMeteredPreferenceController2 meteredPreferenceController2 = 199 new WifiMeteredPreferenceController2(context, wifiEntry); 200 mControllers.add(meteredPreferenceController2); 201 202 final WifiPrivacyPreferenceController2 privacyController2 = 203 new WifiPrivacyPreferenceController2(context); 204 privacyController2.setWifiEntry(wifiEntry); 205 mControllers.add(privacyController2); 206 207 final WifiSubscriptionDetailPreferenceController2 208 wifiSubscriptionDetailPreferenceController2 = 209 new WifiSubscriptionDetailPreferenceController2(context); 210 wifiSubscriptionDetailPreferenceController2.setWifiEntry(wifiEntry); 211 mControllers.add(wifiSubscriptionDetailPreferenceController2); 212 213 // Sets callback listener for wifi dialog. 214 mWifiDialogListeners.add(mWifiDetailPreferenceController2); 215 mWifiDialogListeners.add(privacyController2); 216 mWifiDialogListeners.add(meteredPreferenceController2); 217 218 return mControllers; 219 } 220 221 @Override onSubmit(WifiDialog2 dialog)222 public void onSubmit(WifiDialog2 dialog) { 223 for (WifiDialog2.WifiDialog2Listener listener : mWifiDialogListeners) { 224 listener.onSubmit(dialog); 225 } 226 } 227 setupNetworksDetailTracker()228 private void setupNetworksDetailTracker() { 229 if (mNetworkDetailsTracker != null) { 230 return; 231 } 232 233 final Context context = getContext(); 234 mWorkerThread = new HandlerThread(TAG 235 + "{" + Integer.toHexString(System.identityHashCode(this)) + "}", 236 Process.THREAD_PRIORITY_BACKGROUND); 237 mWorkerThread.start(); 238 final Clock elapsedRealtimeClock = new SimpleClock(ZoneOffset.UTC) { 239 @Override 240 public long millis() { 241 return SystemClock.elapsedRealtime(); 242 } 243 }; 244 245 mNetworkDetailsTracker = NetworkDetailsTracker.createNetworkDetailsTracker( 246 getSettingsLifecycle(), 247 context, 248 context.getSystemService(WifiManager.class), 249 context.getSystemService(ConnectivityManager.class), 250 context.getSystemService(NetworkScoreManager.class), 251 new Handler(Looper.getMainLooper()), 252 mWorkerThread.getThreadHandler(), 253 elapsedRealtimeClock, 254 MAX_SCAN_AGE_MILLIS, 255 SCAN_INTERVAL_MILLIS, 256 getArguments().getString(KEY_CHOSEN_WIFIENTRY_KEY)); 257 } 258 isEditable()259 private boolean isEditable() { 260 if (mNetworkDetailsTracker == null) { 261 return false; 262 } 263 final WifiEntry wifiEntry = mNetworkDetailsTracker.getWifiEntry(); 264 if (wifiEntry == null) { 265 return false; 266 } 267 return wifiEntry.isSaved(); 268 } 269 270 /** 271 * API call for refreshing the preferences in this fragment. 272 */ refreshPreferences()273 public void refreshPreferences() { 274 updatePreferenceStates(); 275 displayPreferenceControllers(); 276 } 277 displayPreferenceControllers()278 protected void displayPreferenceControllers() { 279 final PreferenceScreen screen = getPreferenceScreen(); 280 for (AbstractPreferenceController controller : mControllers) { 281 // WifiDetailPreferenceController2 gets the callback WifiEntryCallback#onUpdated, 282 // it can control the visibility change by itself. 283 // And WifiDetailPreferenceController2#updatePreference renew mEntityHeaderController 284 // instance which will cause icon reset. 285 if (controller instanceof WifiDetailPreferenceController2) { 286 continue; 287 } 288 controller.displayPreference(screen); 289 } 290 } 291 } 292