blob: fc2f8f1541565f85edecc29982ce9caf6c782a34 [file] [log] [blame]
/*
* 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.settingslib.wifi.WifiEntryPreference;
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.getFactory(context)
.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.
}
}