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");
}
}
}
}