1 /*
2  * Copyright (C) 2017 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 static com.android.settings.wifi.ConfigureWifiSettings.WIFI_WAKEUP_REQUEST_CODE;
20 
21 import android.app.Service;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.location.LocationManager;
27 import android.net.wifi.WifiManager;
28 import android.provider.Settings;
29 
30 import androidx.annotation.VisibleForTesting;
31 import androidx.fragment.app.Fragment;
32 import androidx.preference.Preference;
33 import androidx.preference.PreferenceScreen;
34 import androidx.preference.TwoStatePreference;
35 
36 import com.android.settings.R;
37 import com.android.settings.core.TogglePreferenceController;
38 import com.android.settings.utils.AnnotationSpan;
39 import com.android.settingslib.core.lifecycle.LifecycleObserver;
40 import com.android.settingslib.core.lifecycle.events.OnPause;
41 import com.android.settingslib.core.lifecycle.events.OnResume;
42 
43 /**
44  * {@link TogglePreferenceController} that controls whether the Wi-Fi Wakeup feature should be
45  * enabled.
46  */
47 public class WifiWakeupPreferenceController extends TogglePreferenceController implements
48         LifecycleObserver, OnPause, OnResume {
49 
50     private static final String TAG = "WifiWakeupPrefController";
51     private static final String KEY_ENABLE_WIFI_WAKEUP = "enable_wifi_wakeup";
52 
53     private Fragment mFragment;
54 
55     @VisibleForTesting
56     TwoStatePreference mPreference;
57 
58     @VisibleForTesting
59     LocationManager mLocationManager;
60 
61     @VisibleForTesting
62     WifiManager mWifiManager;
63 
64     private final BroadcastReceiver mLocationReceiver = new BroadcastReceiver() {
65         @Override
66         public void onReceive(Context context, Intent intent) {
67             updateState(mPreference);
68         }
69     };
70 
71     private final IntentFilter mLocationFilter =
72             new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
73 
WifiWakeupPreferenceController(Context context)74     public WifiWakeupPreferenceController(Context context) {
75         super(context, KEY_ENABLE_WIFI_WAKEUP);
76         mLocationManager = (LocationManager) context.getSystemService(Service.LOCATION_SERVICE);
77         mWifiManager = context.getSystemService(WifiManager.class);
78     }
79 
setFragment(Fragment hostFragment)80     public void setFragment(Fragment hostFragment) {
81         mFragment = hostFragment;
82     }
83 
84     @Override
displayPreference(PreferenceScreen screen)85     public void displayPreference(PreferenceScreen screen) {
86         super.displayPreference(screen);
87         mPreference = screen.findPreference(getPreferenceKey());
88     }
89 
90     @Override
getAvailabilityStatus()91     public int getAvailabilityStatus() {
92         // Since mFragment is set only when entering Network preferences settings. So when
93         // mFragment == null, we can assume that the object is created by Search settings.
94         // When Search settings is called, if the dependent condition is not enabled, then
95         // return DISABLED_DEPENDENT_SETTING to hide the toggle.
96         if (mFragment == null && (!getLocationEnabled() || !getWifiScanningEnabled())) {
97             return DISABLED_DEPENDENT_SETTING;
98         }
99         return AVAILABLE;
100     }
101 
102     @Override
isChecked()103     public boolean isChecked() {
104         return getWifiWakeupEnabled()
105                 && getWifiScanningEnabled()
106                 && getLocationEnabled();
107     }
108 
109     @Override
setChecked(boolean isChecked)110     public boolean setChecked(boolean isChecked) {
111         if (isChecked) {
112             if (!getLocationEnabled()) {
113                 if (mFragment == null) {
114                     throw new IllegalStateException("No fragment to start activity");
115                 }
116 
117                 final Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
118                         .setPackage(mContext.getPackageName());
119                 mFragment.startActivityForResult(intent, WIFI_WAKEUP_REQUEST_CODE);
120                 return false;
121             } else if (!getWifiScanningEnabled()) {
122                 showScanningDialog();
123                 return false;
124             }
125         }
126 
127         setWifiWakeupEnabled(isChecked);
128         return true;
129     }
130 
131     @Override
updateState(Preference preference)132     public void updateState(Preference preference) {
133         super.updateState(preference);
134         refreshSummary(preference);
135     }
136 
137     @Override
getSummary()138     public CharSequence getSummary() {
139         if (!getLocationEnabled()) {
140             return getNoLocationSummary();
141         } else {
142             return mContext.getText(R.string.wifi_wakeup_summary);
143         }
144     }
145 
146     @Override
getSliceHighlightMenuRes()147     public int getSliceHighlightMenuRes() {
148         return R.string.menu_key_network;
149     }
150 
151     @VisibleForTesting
getNoLocationSummary()152     CharSequence getNoLocationSummary() {
153         AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo("link", null);
154         CharSequence locationText = mContext.getText(R.string.wifi_wakeup_summary_no_location);
155         return AnnotationSpan.linkify(locationText, linkInfo);
156     }
157 
onActivityResult(int requestCode, int resultCode)158     public void onActivityResult(int requestCode, int resultCode) {
159         if (requestCode != WIFI_WAKEUP_REQUEST_CODE) {
160             return;
161         }
162         if (getLocationEnabled() && getWifiScanningEnabled()) {
163             setWifiWakeupEnabled(true);
164             updateState(mPreference);
165         }
166     }
167 
getLocationEnabled()168     private boolean getLocationEnabled() {
169         return mLocationManager.isLocationEnabled();
170     }
171 
getWifiScanningEnabled()172     private boolean getWifiScanningEnabled() {
173         return mWifiManager.isScanAlwaysAvailable();
174     }
175 
showScanningDialog()176     private void showScanningDialog() {
177         final WifiScanningRequiredFragment dialogFragment =
178                 WifiScanningRequiredFragment.newInstance();
179         dialogFragment.setTargetFragment(mFragment, WIFI_WAKEUP_REQUEST_CODE /* requestCode */);
180         dialogFragment.show(mFragment.getFragmentManager(), TAG);
181     }
182 
getWifiWakeupEnabled()183     private boolean getWifiWakeupEnabled() {
184         return mWifiManager.isAutoWakeupEnabled();
185     }
186 
setWifiWakeupEnabled(boolean enabled)187     private void setWifiWakeupEnabled(boolean enabled) {
188         mWifiManager.setAutoWakeupEnabled(enabled);
189     }
190 
191     @Override
onResume()192     public void onResume() {
193         mContext.registerReceiver(mLocationReceiver, mLocationFilter);
194     }
195 
196     @Override
onPause()197     public void onPause() {
198         mContext.unregisterReceiver(mLocationReceiver);
199     }
200 }
201