• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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;
18 
19 import android.content.Context;
20 import android.os.Bundle;
21 import android.os.Handler;
22 import android.os.HandlerThread;
23 import android.os.Looper;
24 import android.os.Process;
25 import android.os.SimpleClock;
26 import android.os.SystemClock;
27 
28 import androidx.annotation.VisibleForTesting;
29 import androidx.lifecycle.LifecycleObserver;
30 import androidx.lifecycle.OnLifecycleEvent;
31 import androidx.preference.PreferenceGroup;
32 import androidx.preference.PreferenceScreen;
33 
34 import com.android.settings.R;
35 import com.android.settings.core.SubSettingLauncher;
36 import com.android.settings.overlay.FeatureFactory;
37 import com.android.settings.wifi.details.WifiNetworkDetailsFragment;
38 import com.android.settingslib.core.AbstractPreferenceController;
39 import com.android.settingslib.core.lifecycle.Lifecycle;
40 import com.android.wifitrackerlib.WifiEntry;
41 import com.android.wifitrackerlib.WifiPickerTracker;
42 
43 import java.time.Clock;
44 import java.time.ZoneOffset;
45 
46 // TODO(b/151133650): Replace AbstractPreferenceController with BasePreferenceController.
47 /**
48  * This places a preference into a PreferenceGroup owned by some parent
49  * controller class when there is a wifi connection present.
50  */
51 public class WifiConnectionPreferenceController extends AbstractPreferenceController implements
52         WifiPickerTracker.WifiPickerTrackerCallback, LifecycleObserver {
53 
54     private static final String TAG = "WifiConnPrefCtrl";
55 
56     private static final String KEY = "active_wifi_connection";
57 
58     // Max age of tracked WifiEntries.
59     private static final long MAX_SCAN_AGE_MILLIS = 15_000;
60     // Interval between initiating WifiPickerTracker scans.
61     private static final long SCAN_INTERVAL_MILLIS = 10_000;
62 
63     private UpdateListener mUpdateListener;
64     private Context mPrefContext;
65     private String mPreferenceGroupKey;
66     private PreferenceGroup mPreferenceGroup;
67     @VisibleForTesting
68     public WifiPickerTracker mWifiPickerTracker;
69     private WifiEntryPreference mPreference;
70     private int order;
71     private int mMetricsCategory;
72     // Worker thread used for WifiPickerTracker work.
73     private HandlerThread mWorkerThread;
74 
75     /**
76      * Used to notify a parent controller that this controller has changed in availability, or has
77      * updated the content in the preference that it manages.
78      */
79     public interface UpdateListener {
onChildrenUpdated()80         void onChildrenUpdated();
81     }
82 
83     /**
84      * @param context            the context for the UI where we're placing the preference
85      * @param lifecycle          for listening to lifecycle events for the UI
86      * @param updateListener     for notifying a parent controller of changes
87      * @param preferenceGroupKey the key to use to lookup the PreferenceGroup where this controller
88      *                           will add its preference
89      * @param order              the order that the preference added by this controller should use -
90      *                           useful when this preference needs to be ordered in a specific way
91      *                           relative to others in the PreferenceGroup
92      * @param metricsCategory    - the category to use as the source when handling the click on the
93      *                           pref to go to the wifi connection detail page
94      */
WifiConnectionPreferenceController(Context context, Lifecycle lifecycle, UpdateListener updateListener, String preferenceGroupKey, int order, int metricsCategory)95     public WifiConnectionPreferenceController(Context context, Lifecycle lifecycle,
96             UpdateListener updateListener, String preferenceGroupKey, int order,
97             int metricsCategory) {
98         super(context);
99         lifecycle.addObserver(this);
100         mUpdateListener = updateListener;
101         mPreferenceGroupKey = preferenceGroupKey;
102         this.order = order;
103         mMetricsCategory = metricsCategory;
104 
105         mWorkerThread = new HandlerThread(
106                 TAG + "{" + Integer.toHexString(System.identityHashCode(this)) + "}",
107                 Process.THREAD_PRIORITY_BACKGROUND);
108         mWorkerThread.start();
109         final Clock elapsedRealtimeClock = new SimpleClock(ZoneOffset.UTC) {
110             @Override
111             public long millis() {
112                 return SystemClock.elapsedRealtime();
113             }
114         };
115         mWifiPickerTracker = FeatureFactory.getFeatureFactory()
116                 .getWifiTrackerLibProvider()
117                 .createWifiPickerTracker(lifecycle, context,
118                         new Handler(Looper.getMainLooper()),
119                         mWorkerThread.getThreadHandler(),
120                         elapsedRealtimeClock,
121                         MAX_SCAN_AGE_MILLIS,
122                         SCAN_INTERVAL_MILLIS,
123                         this);
124     }
125 
126     /**
127      * This event is triggered when users click back button at 'Network & internet'.
128      */
129     @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
onDestroy()130     public void onDestroy() {
131         mWorkerThread.quit();
132     }
133 
134     @Override
isAvailable()135     public boolean isAvailable() {
136         return mWifiPickerTracker.getConnectedWifiEntry() != null;
137     }
138 
139     @Override
getPreferenceKey()140     public String getPreferenceKey() {
141         return KEY;
142     }
143 
144     @Override
displayPreference(PreferenceScreen screen)145     public void displayPreference(PreferenceScreen screen) {
146         super.displayPreference(screen);
147         mPreferenceGroup = screen.findPreference(mPreferenceGroupKey);
148         mPrefContext = screen.getContext();
149         update();
150     }
151 
updatePreference(WifiEntry wifiEntry)152     private void updatePreference(WifiEntry wifiEntry) {
153         if (mPreference != null) {
154             mPreferenceGroup.removePreference(mPreference);
155             mPreference = null;
156         }
157         if (wifiEntry == null || mPrefContext == null) {
158             return;
159         }
160 
161         mPreference = new WifiEntryPreference(mPrefContext, wifiEntry);
162         mPreference.setKey(KEY);
163         mPreference.refresh();
164         mPreference.setOrder(order);
165         mPreference.setOnPreferenceClickListener(pref -> {
166             final Bundle args = new Bundle();
167             args.putString(WifiNetworkDetailsFragment.KEY_CHOSEN_WIFIENTRY_KEY,
168                     wifiEntry.getKey());
169             new SubSettingLauncher(mPrefContext)
170                     .setTitleRes(R.string.pref_title_network_details)
171                     .setDestination(WifiNetworkDetailsFragment.class.getName())
172                     .setArguments(args)
173                     .setSourceMetricsCategory(mMetricsCategory)
174                     .launch();
175             return true;
176         });
177         mPreferenceGroup.addPreference(mPreference);
178     }
179 
update()180     private void update() {
181         final WifiEntry connectedWifiEntry = mWifiPickerTracker.getConnectedWifiEntry();
182         if (connectedWifiEntry == null) {
183             updatePreference(null);
184         } else {
185             if (mPreference == null || !mPreference.getWifiEntry().equals(connectedWifiEntry)) {
186                 updatePreference(connectedWifiEntry);
187             } else if (mPreference != null) {
188                 mPreference.refresh();
189             }
190         }
191         mUpdateListener.onChildrenUpdated();
192     }
193 
194     /** Called when the state of Wifi has changed. */
195     @Override
onWifiStateChanged()196     public void onWifiStateChanged() {
197         update();
198     }
199 
200     /**
201      * Update the results when data changes.
202      */
203     @Override
onWifiEntriesChanged()204     public void onWifiEntriesChanged() {
205         update();
206     }
207 
208     @Override
onNumSavedSubscriptionsChanged()209     public void onNumSavedSubscriptionsChanged() {
210         // Do nothing.
211     }
212 
213     @Override
onNumSavedNetworksChanged()214     public void onNumSavedNetworksChanged() {
215         // Do nothing.
216     }
217 }
218