| /* |
| * Copyright (C) 2018 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; |
| |
| import android.content.Context; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.HandlerThread; |
| import android.os.Looper; |
| import android.os.Process; |
| import android.os.SimpleClock; |
| import android.os.SystemClock; |
| |
| import androidx.annotation.VisibleForTesting; |
| import androidx.lifecycle.LifecycleObserver; |
| import androidx.lifecycle.OnLifecycleEvent; |
| import androidx.preference.PreferenceGroup; |
| import androidx.preference.PreferenceScreen; |
| |
| import com.android.settings.R; |
| import com.android.settings.core.SubSettingLauncher; |
| import com.android.settings.overlay.FeatureFactory; |
| import com.android.settings.wifi.details.WifiNetworkDetailsFragment; |
| import com.android.settingslib.core.AbstractPreferenceController; |
| import com.android.settingslib.core.lifecycle.Lifecycle; |
| import com.android.wifitrackerlib.WifiEntry; |
| import com.android.wifitrackerlib.WifiPickerTracker; |
| |
| import java.time.Clock; |
| import java.time.ZoneOffset; |
| |
| // TODO(b/151133650): Replace AbstractPreferenceController with BasePreferenceController. |
| /** |
| * This places a preference into a PreferenceGroup owned by some parent |
| * controller class when there is a wifi connection present. |
| */ |
| public class WifiConnectionPreferenceController extends AbstractPreferenceController implements |
| WifiPickerTracker.WifiPickerTrackerCallback, LifecycleObserver { |
| |
| private static final String TAG = "WifiConnPrefCtrl"; |
| |
| private static final String KEY = "active_wifi_connection"; |
| |
| // Max age of tracked WifiEntries. |
| private static final long MAX_SCAN_AGE_MILLIS = 15_000; |
| // Interval between initiating WifiPickerTracker scans. |
| private static final long SCAN_INTERVAL_MILLIS = 10_000; |
| |
| private UpdateListener mUpdateListener; |
| private Context mPrefContext; |
| private String mPreferenceGroupKey; |
| private PreferenceGroup mPreferenceGroup; |
| @VisibleForTesting |
| public WifiPickerTracker mWifiPickerTracker; |
| private WifiEntryPreference mPreference; |
| private int order; |
| private int mMetricsCategory; |
| // Worker thread used for WifiPickerTracker work. |
| private HandlerThread mWorkerThread; |
| |
| /** |
| * Used to notify a parent controller that this controller has changed in availability, or has |
| * updated the content in the preference that it manages. |
| */ |
| public interface UpdateListener { |
| void onChildrenUpdated(); |
| } |
| |
| /** |
| * @param context the context for the UI where we're placing the preference |
| * @param lifecycle for listening to lifecycle events for the UI |
| * @param updateListener for notifying a parent controller of changes |
| * @param preferenceGroupKey the key to use to lookup the PreferenceGroup where this controller |
| * will add its preference |
| * @param order the order that the preference added by this controller should use - |
| * useful when this preference needs to be ordered in a specific way |
| * relative to others in the PreferenceGroup |
| * @param metricsCategory - the category to use as the source when handling the click on the |
| * pref to go to the wifi connection detail page |
| */ |
| public WifiConnectionPreferenceController(Context context, Lifecycle lifecycle, |
| UpdateListener updateListener, String preferenceGroupKey, int order, |
| int metricsCategory) { |
| super(context); |
| lifecycle.addObserver(this); |
| mUpdateListener = updateListener; |
| mPreferenceGroupKey = preferenceGroupKey; |
| this.order = order; |
| mMetricsCategory = metricsCategory; |
| |
| mWorkerThread = new HandlerThread( |
| TAG + "{" + Integer.toHexString(System.identityHashCode(this)) + "}", |
| Process.THREAD_PRIORITY_BACKGROUND); |
| mWorkerThread.start(); |
| final Clock elapsedRealtimeClock = new SimpleClock(ZoneOffset.UTC) { |
| @Override |
| public long millis() { |
| return SystemClock.elapsedRealtime(); |
| } |
| }; |
| mWifiPickerTracker = FeatureFactory.getFeatureFactory() |
| .getWifiTrackerLibProvider() |
| .createWifiPickerTracker(lifecycle, context, |
| new Handler(Looper.getMainLooper()), |
| mWorkerThread.getThreadHandler(), |
| elapsedRealtimeClock, |
| MAX_SCAN_AGE_MILLIS, |
| SCAN_INTERVAL_MILLIS, |
| this); |
| } |
| |
| /** |
| * This event is triggered when users click back button at 'Network & internet'. |
| */ |
| @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) |
| public void onDestroy() { |
| mWorkerThread.quit(); |
| } |
| |
| @Override |
| public boolean isAvailable() { |
| return mWifiPickerTracker.getConnectedWifiEntry() != null; |
| } |
| |
| @Override |
| public String getPreferenceKey() { |
| return KEY; |
| } |
| |
| @Override |
| public void displayPreference(PreferenceScreen screen) { |
| super.displayPreference(screen); |
| mPreferenceGroup = screen.findPreference(mPreferenceGroupKey); |
| mPrefContext = screen.getContext(); |
| update(); |
| } |
| |
| private void updatePreference(WifiEntry wifiEntry) { |
| if (mPreference != null) { |
| mPreferenceGroup.removePreference(mPreference); |
| mPreference = null; |
| } |
| if (wifiEntry == null || mPrefContext == null) { |
| return; |
| } |
| |
| mPreference = new WifiEntryPreference(mPrefContext, wifiEntry); |
| mPreference.setKey(KEY); |
| mPreference.refresh(); |
| mPreference.setOrder(order); |
| mPreference.setOnPreferenceClickListener(pref -> { |
| final Bundle args = new Bundle(); |
| args.putString(WifiNetworkDetailsFragment.KEY_CHOSEN_WIFIENTRY_KEY, |
| wifiEntry.getKey()); |
| new SubSettingLauncher(mPrefContext) |
| .setTitleRes(R.string.pref_title_network_details) |
| .setDestination(WifiNetworkDetailsFragment.class.getName()) |
| .setArguments(args) |
| .setSourceMetricsCategory(mMetricsCategory) |
| .launch(); |
| return true; |
| }); |
| mPreferenceGroup.addPreference(mPreference); |
| } |
| |
| private void update() { |
| final WifiEntry connectedWifiEntry = mWifiPickerTracker.getConnectedWifiEntry(); |
| if (connectedWifiEntry == null) { |
| updatePreference(null); |
| } else { |
| if (mPreference == null || !mPreference.getWifiEntry().equals(connectedWifiEntry)) { |
| updatePreference(connectedWifiEntry); |
| } else if (mPreference != null) { |
| mPreference.refresh(); |
| } |
| } |
| mUpdateListener.onChildrenUpdated(); |
| } |
| |
| /** Called when the state of Wifi has changed. */ |
| @Override |
| public void onWifiStateChanged() { |
| update(); |
| } |
| |
| /** |
| * Update the results when data changes. |
| */ |
| @Override |
| public void onWifiEntriesChanged() { |
| update(); |
| } |
| |
| @Override |
| public void onNumSavedSubscriptionsChanged() { |
| // Do nothing. |
| } |
| |
| @Override |
| public void onNumSavedNetworksChanged() { |
| // Do nothing. |
| } |
| } |