1 /* 2 * Copyright 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.server.wifi; 18 19 import static com.android.server.wifi.WakeupNotificationFactory.ACTION_DISMISS_NOTIFICATION; 20 import static com.android.server.wifi.WakeupNotificationFactory.ACTION_OPEN_WIFI_PREFERENCES; 21 import static com.android.server.wifi.WakeupNotificationFactory.ACTION_TURN_OFF_WIFI_WAKE; 22 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.net.wifi.WifiContext; 28 import android.os.Handler; 29 import android.os.SystemClock; 30 import android.os.UserHandle; 31 import android.provider.Settings; 32 import android.text.format.DateUtils; 33 import android.util.Log; 34 35 import com.android.internal.annotations.VisibleForTesting; 36 37 /** 38 * Manages the WiFi Wake onboarding notification. 39 * 40 * <p>If a user disables wifi with Wifi Wake enabled, this notification is shown to explain that 41 * wifi may turn back on automatically. It will be displayed up to 3 times, or until the 42 * user either interacts with the onboarding notification in some way (e.g. dismiss, tap) or 43 * manually enables/disables the feature in WifiSettings. 44 */ 45 public class WakeupOnboarding { 46 47 private static final String TAG = "WakeupOnboarding"; 48 49 @VisibleForTesting 50 static final int NOTIFICATIONS_UNTIL_ONBOARDED = 3; 51 @VisibleForTesting 52 static final long REQUIRED_NOTIFICATION_DELAY = DateUtils.DAY_IN_MILLIS; 53 private static final long NOT_SHOWN_TIMESTAMP = -1; 54 55 private final WifiContext mContext; 56 private final WakeupNotificationFactory mWakeupNotificationFactory; 57 private final WifiNotificationManager mNotificationManager; 58 private final Handler mHandler; 59 private final WifiConfigManager mWifiConfigManager; 60 private final IntentFilter mIntentFilter; 61 private final FrameworkFacade mFrameworkFacade; 62 63 private boolean mIsOnboarded; 64 private int mTotalNotificationsShown; 65 private long mLastShownTimestamp = NOT_SHOWN_TIMESTAMP; 66 private boolean mIsNotificationShowing; 67 68 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 69 @Override 70 public void onReceive(Context context, Intent intent) { 71 switch (intent.getAction()) { 72 case ACTION_TURN_OFF_WIFI_WAKE: 73 mFrameworkFacade.setIntegerSetting(mContext, 74 Settings.Global.WIFI_WAKEUP_ENABLED, 0); 75 dismissNotification(true /* shouldOnboard */); 76 break; 77 case ACTION_OPEN_WIFI_PREFERENCES: 78 // Close notification drawer before opening preferences. 79 mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); 80 mContext.startActivityAsUser(new Intent(Settings.ACTION_WIFI_IP_SETTINGS) 81 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), UserHandle.CURRENT); 82 dismissNotification(true /* shouldOnboard */); 83 break; 84 case ACTION_DISMISS_NOTIFICATION: 85 dismissNotification(true /* shouldOnboard */); 86 break; 87 default: 88 Log.e(TAG, "Unknown action " + intent.getAction()); 89 } 90 } 91 }; 92 WakeupOnboarding( WifiContext context, WifiConfigManager wifiConfigManager, Handler handler, FrameworkFacade frameworkFacade, WakeupNotificationFactory wakeupNotificationFactory, WifiNotificationManager wifiNotificationManager)93 public WakeupOnboarding( 94 WifiContext context, 95 WifiConfigManager wifiConfigManager, 96 Handler handler, 97 FrameworkFacade frameworkFacade, 98 WakeupNotificationFactory wakeupNotificationFactory, 99 WifiNotificationManager wifiNotificationManager) { 100 mContext = context; 101 mWifiConfigManager = wifiConfigManager; 102 mHandler = handler; 103 mFrameworkFacade = frameworkFacade; 104 mWakeupNotificationFactory = wakeupNotificationFactory; 105 mNotificationManager = wifiNotificationManager; 106 107 mIntentFilter = new IntentFilter(); 108 mIntentFilter.addAction(ACTION_TURN_OFF_WIFI_WAKE); 109 mIntentFilter.addAction(ACTION_DISMISS_NOTIFICATION); 110 mIntentFilter.addAction(ACTION_OPEN_WIFI_PREFERENCES); 111 } 112 113 /** Returns whether the user is onboarded. */ isOnboarded()114 public boolean isOnboarded() { 115 return mIsOnboarded; 116 } 117 118 /** Shows the onboarding notification if applicable. */ maybeShowNotification()119 public void maybeShowNotification() { 120 maybeShowNotification(SystemClock.elapsedRealtime()); 121 } 122 123 @VisibleForTesting maybeShowNotification(long timestamp)124 void maybeShowNotification(long timestamp) { 125 if (!shouldShowNotification(timestamp)) { 126 return; 127 } 128 Log.d(TAG, "Showing onboarding notification."); 129 130 incrementTotalNotificationsShown(); 131 mIsNotificationShowing = true; 132 mLastShownTimestamp = timestamp; 133 134 mContext.registerReceiver(mBroadcastReceiver, mIntentFilter, 135 null /* broadcastPermission */, mHandler); 136 mNotificationManager.notify(WakeupNotificationFactory.ONBOARD_ID, 137 mWakeupNotificationFactory.createOnboardingNotification()); 138 } 139 140 /** 141 * Increment the total number of shown notifications and onboard the user if reached the 142 * required amount. 143 */ incrementTotalNotificationsShown()144 private void incrementTotalNotificationsShown() { 145 mTotalNotificationsShown++; 146 if (mTotalNotificationsShown >= NOTIFICATIONS_UNTIL_ONBOARDED) { 147 setOnboarded(); 148 } else { 149 mWifiConfigManager.saveToStore(); 150 } 151 } 152 shouldShowNotification(long timestamp)153 private boolean shouldShowNotification(long timestamp) { 154 if (isOnboarded() || mIsNotificationShowing) { 155 return false; 156 } 157 158 return mLastShownTimestamp == NOT_SHOWN_TIMESTAMP 159 || (timestamp - mLastShownTimestamp) > REQUIRED_NOTIFICATION_DELAY; 160 } 161 162 /** Handles onboarding cleanup on stop. */ onStop()163 public void onStop() { 164 dismissNotification(false /* shouldOnboard */); 165 } 166 dismissNotification(boolean shouldOnboard)167 private void dismissNotification(boolean shouldOnboard) { 168 if (!mIsNotificationShowing) { 169 return; 170 } 171 172 if (shouldOnboard) { 173 setOnboarded(); 174 } 175 176 mContext.unregisterReceiver(mBroadcastReceiver); 177 mNotificationManager.cancel(WakeupNotificationFactory.ONBOARD_ID); 178 mIsNotificationShowing = false; 179 } 180 181 /** Sets the user as onboarded and persists to store. */ setOnboarded()182 public void setOnboarded() { 183 if (mIsOnboarded) { 184 return; 185 } 186 Log.d(TAG, "Setting user as onboarded."); 187 mIsOnboarded = true; 188 mWifiConfigManager.saveToStore(); 189 } 190 191 /** Returns the {@link WakeupConfigStoreData.DataSource} for the onboarded status. */ getIsOnboadedDataSource()192 public WakeupConfigStoreData.DataSource<Boolean> getIsOnboadedDataSource() { 193 return new IsOnboardedDataSource(); 194 } 195 196 /** Returns the {@link WakeupConfigStoreData.DataSource} for the notification status. */ getNotificationsDataSource()197 public WakeupConfigStoreData.DataSource<Integer> getNotificationsDataSource() { 198 return new NotificationsDataSource(); 199 } 200 201 private class IsOnboardedDataSource implements WakeupConfigStoreData.DataSource<Boolean> { 202 203 @Override getData()204 public Boolean getData() { 205 return mIsOnboarded; 206 } 207 208 @Override setData(Boolean data)209 public void setData(Boolean data) { 210 mIsOnboarded = data; 211 } 212 } 213 214 private class NotificationsDataSource implements WakeupConfigStoreData.DataSource<Integer> { 215 216 @Override getData()217 public Integer getData() { 218 return mTotalNotificationsShown; 219 } 220 221 @Override setData(Integer data)222 public void setData(Integer data) { 223 mTotalNotificationsShown = data; 224 } 225 } 226 } 227