android 8.1 监控省电模式,触发各种开关
1.流程,思路
首先监听一个系统开机广播,开机完成后启动一个服务去注册我们要监听的系统广播,接收到之后做具体处理,
在这个流程中,遇到几个头疼的问题,第一就是监听开机广播后服务启动问题,在Android8.0(26) 以后,主要为了性能的提升,比如省电,对APP(targetsdk >= 26)的控制加强了很多。
比如不能监听大部分静态注册(在Manifest里配置)的系统广播,APP层自己的静态广播也不允许了,只能动态注册(在代码里注册),不过官网也推荐可以使用JobScheduler 代替静态广播,也是不错的方法;
还有就是启动服务也有很大的限制,APP(targetsdk >= 26)不在前台的时候再也不能启动后台服务(startService), 只能启动前台服务(两种情况,第一种是APP本身处于前台即可见状态,第二种是直接
startForegroundService),这样也是为了让用户知道有服务在运行,对于APP(targetsdk < 26)的可以正常使用,但是Settings也可以对其进行相同的控制,官网建议都用前台服务代替。
2. 具体步骤
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(Intent.ACTION_BOOT_COMPLETED.equals(action)) {
Intent service = new Intent(context, RegisterService.class);
context.startService(service);
}
}
}
public class RegisterService extends Service {
@Override
public void onCreate() {
registerB();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void registerB() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
registerReceiver(new BatterySaverGlobalReceiver(), intentFilter);
}
}
public class BatterySaverGlobalReceiver extends BroadcastReceiver {
private static final String TAG = "BatterySaverGlobalReceiver";
private static final boolean DEBUG = true;
private static final String SHARED_PREF_NAME_POWER_SAVE_MODE = "power_save_mode_settings";
private static final String PREF_KEY_SCREEN_OFF_TIMEOUT = "screen_off_timeout";
private Context mContext;
private static final String PREF_KEY_LOCATION_MODE = "location_mode";
private static final String PREF_KEY_BLUETOOTH_ENABLED = "bt_enabled";
private static final String PREF_KEY_WIFI_ENABLED = "wifi_enabled";
private static final String PREF_KEY_WIFI_AP_ENABLED = "wifi_ap_enabled";
private static final String PREF_KEY_NFC_ENABLED = "nfc_enabled";
private static final String PREF_KEY_MOBILE_DATA_ENABLED= "mobile_data_enabled";
private BluetoothAdapter mBlueToothAdapter;
private WifiManager mWifiManager;
private NfcAdapter mNfcAdapter;
private ConnectivityManager mConnManager;
private TelephonyManager mTelephonyManager;
@Override
public void onReceive(Context context, Intent intent) {
mContext = context;
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
String action = intent.getAction();
android.util.Log.d(TAG, "onReceive action : " + action);
initValues();
if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
final boolean mode = pm.isPowerSaveMode();
if(DEBUG) {
android.util.Log.d(TAG, "onPowerSaveModeChanged isPowerSaveMode :" + mode);
}
if(mode) {
saveSettings();
setScreenOffTimeout(30*1000);
setLocationMode(Settings.Secure.LOCATION_MODE_OFF);
setBtEnabled(false);
mWifiManager.setWifiEnabled(false);
setWifiApEnabled(false);
setNfcEnabled(false);
mTelephonyManager.setDataEnabled(false);
} else {
restoreSettings();
}
}
}
private void initValues() {
if (mBlueToothAdapter == null) {
mBlueToothAdapter = BluetoothAdapter.getDefaultAdapter();
}
if (mWifiManager == null) {
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
}
if (mNfcAdapter == null) {
mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext);
}
if (mConnManager == null) {
mConnManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
}
if (mTelephonyManager == null) {
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
}
}
private void saveSettings() {
if(DEBUG) {
android.util.Log.d(TAG, "saveSettings");
}
int timeout = 0;
int locationMode = -1;
try {
timeout = Settings.System.getInt(mContext.getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT);
locationMode = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
boolean isBtEnabled = mBlueToothAdapter.isEnabled();
boolean isWifiEnabled = mWifiManager.isWifiEnabled();
boolean isWifiApEnabled = mWifiManager.isWifiApEnabled();
boolean isNfcEnabled = mNfcAdapter.isEnabled();
boolean isMobileDataEnabled = mTelephonyManager.isDataEnabled();
SharedPreferences sharedPref = getPowerSaveModeSharedPref();
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt(PREF_KEY_SCREEN_OFF_TIMEOUT, timeout);
editor.putInt(PREF_KEY_LOCATION_MODE, locationMode);
editor.putBoolean(PREF_KEY_BLUETOOTH_ENABLED, isBtEnabled);
editor.putBoolean(PREF_KEY_WIFI_ENABLED, isWifiEnabled);
editor.putBoolean(PREF_KEY_WIFI_AP_ENABLED, isWifiApEnabled);
editor.putBoolean(PREF_KEY_NFC_ENABLED, isNfcEnabled);
editor.putBoolean(PREF_KEY_MOBILE_DATA_ENABLED, isMobileDataEnabled);
editor.commit();
if(DEBUG) {
android.util.Log.d(TAG, "timeout :" + timeout +
" ,locationMode : " + locationMode + ", isBtEnabled : " + isBtEnabled +
", isWifiEnabled : " + isWifiEnabled + " ,isNfcEnabled : " + isNfcEnabled +
", isMobileDataEnabled : " + isMobileDataEnabled + ", isWifiApEnabled : " + isWifiApEnabled);
}
}
private void restoreSettings() {
SharedPreferences sharedPref = getPowerSaveModeSharedPref();
int timeout = sharedPref.getInt(PREF_KEY_SCREEN_OFF_TIMEOUT, 1*60*1000);
setScreenOffTimeout(timeout);
if(DEBUG) {
android.util.Log.d(TAG, "restoreSettings timeout :" + timeout);
}
int locationMode = sharedPref.getInt(PREF_KEY_LOCATION_MODE, -1);
setLocationMode(locationMode);
boolean isBtEnabled = sharedPref.getBoolean(PREF_KEY_BLUETOOTH_ENABLED, false);
setBtEnabled(isBtEnabled);
boolean isWifiEnabled = sharedPref.getBoolean(PREF_KEY_WIFI_ENABLED, false);
mWifiManager.setWifiEnabled(isWifiEnabled);
boolean isWifiApEnabled = sharedPref.getBoolean(PREF_KEY_WIFI_AP_ENABLED, false);
setWifiApEnabled(isWifiApEnabled);
boolean isNfcEnabled = sharedPref.getBoolean(PREF_KEY_NFC_ENABLED, false);
setNfcEnabled(isNfcEnabled);
boolean isMobileDataEnabled = sharedPref.getBoolean(PREF_KEY_MOBILE_DATA_ENABLED, false);
mTelephonyManager.setDataEnabled(isMobileDataEnabled);
}
private SharedPreferences getPowerSaveModeSharedPref() {
return mContext.getSharedPreferences(SHARED_PREF_NAME_POWER_SAVE_MODE, Context.MODE_PRIVATE);
}
private void setScreenOffTimeout(int timeout) {
Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, timeout);
}
private void setLocationMode(int mode) {
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.LOCATION_MODE, mode);
}
private void setBtEnabled(boolean enabled) {
if(enabled) {
mBlueToothAdapter.enable();
} else {
mBlueToothAdapter.disable();
}
}
private void setNfcEnabled(boolean enabled) {
if (enabled) {
mNfcAdapter.enable();
} else {
mNfcAdapter.disable();
}
}
private void setWifiApEnabled(boolean enabled) {
if (enabled) {
mConnManager.startTethering(ConnectivityManager.TETHERING_WIFI,
true, new OnStartTetheringCallback());
} else {
mConnManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
}
}
private static final class OnStartTetheringCallback
extends ConnectivityManager.OnStartTetheringCallback {
@Override
public void onTetheringStarted() {
if(DEBUG) {
android.util.Log.d(TAG, "onTetheringStarted");
}
}
@Override
public void onTetheringFailed() {
if(DEBUG) {
android.util.Log.d(TAG, "onTetheringFailed");
}
}
}
}