Takeaway:
Recently, I was developing a regular reminder service, similar to an alarm clock, and encountered a problem. When the APP was running in the background, the user turned off the phone screen (the phone went into the off-screen sleep state). At this time, using the system vibration and alarm clock did not work. why? The same is off the screen sleep state, why QQ, wechat and so on can have a message reminder, but my APP is not, it is best not its sister, Baidu some time to find a solution.
Solution:
Back to the background, we want to continue to do something, of course, using the Service.
2. Define a BroadcastReceiver in the Activity to receive Service commands.
3. Add a flag to the Activity (must be added) to allow the message to be displayed when the screen is locked (unlock the screen).
When the message reminder needs to be sent to the user, the command is sent to the broadcast receiver and then executed by the broadcast receiver.
Specific steps:
Mainactivity.class; onCreate();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/** * Add flag bits to allow the message to be displayed on the lock screen. In screen lock mode * 2. Unlock * 3. (Optional) Keep the screen on * 4. Open screen * When the Activity starts, it unlocks and displays on the bright screen */
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED // Display in the locked state
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD / / unlock
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON // Keep the screen bright
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); // Open the screen
}
Copy the code
Define an inner class broadcast receiver in the mainActivity. class activity as follows:
/** * Defines the broadcast receiver used to perform the requirements of the Service (inner class) */
private class ServiceNeedBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
/*------------ here is the code to execute in the Activity ----------*/
// The phone vibrates
ToolUtils.playVibrate(MainActivity.this.true);
// Play the default alarm tone
ToolUtils.defaultAlarmMediaPlayer(MainActivity.this);
/*------------ here is the code to execute in the Activity ----------*/}}Copy the code
Here is the vibration and alarm code in the ToolUtils. Java utility class:
package com.xiao7.pump.Utils;
import android.annotation.SuppressLint;
import android.app.KeyguardManager;
import android.app.Service;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.PowerManager;
import android.os.Vibrator;
public class ToolUtils {
private static Vibrator vibrator;
private static PowerManager.WakeLock wakeLock;
/** * Wake up the phone screen and unlock **@param context
*/
@SuppressLint("InvalidWakeLockTag")
public static void acquire(Context context) {
try {
// Get the power manager object
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
// Get the PowerManager.WakeLock object
wakeLock = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, "bright");
// Light the screen for 30 seconds
wakeLock.acquire(30 * 1000);
// Off screen (release lock)
if (null! = wakeLock) { wakeLock.release(); } KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);// The "unLock" parameter is used as the Tag in LogCat for debugging
KeyguardManager.KeyguardLock kl = km.newKeyguardLock("unLock");
/ / unlock
kl.disableKeyguard();
} catch (Exception ex) {
}
}
/** * Mobile phone vibrates **@param context
* @paramIsRepeat Whether to repeat vibration */
public static void playVibrate(Context context, boolean isRepeat) {
Long []{1000, 500, 2000}; long[]{1000, 500, 2000}; * Don't forget to ask for permission to vibrate in the AndroidManifest profile */
try {
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
long[] patern = new long[] {1000.500.2000};
AudioAttributes audioAttributes = null;
/** * for android7.0 or higher version vibration * note: if you find that the 5.0 or 6.0 version does not vibration after the app is back in the background, then just change the build.version_codes.n version number below. */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
audioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM) //key
.build();
vibrator.vibrate(patern, isRepeat ? 1 : -1, audioAttributes);
}else {
vibrator.vibrate(patern, isRepeat ? 1 : -1); }}catch (Exception ex) {
}
}
/** * Turn off vibration */
public static void closeVibrate(a) {
if(vibrator ! =null) {
vibrator.cancel();
vibrator = null; }}/** * Play the default announcements **@returnMediaPlayer object *@throws Exception
*/
public static void defaultMediaPlayer(Context mContext) {
try {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(mContext, notification);
r.play();
} catch (Exception ex) {
}
}
/** * Play the default system ringtone **@returnMediaPlayer object *@throws Exception
*/
public static void defaultCallMediaPlayer(Context mContext) {
try {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
Ringtone r = RingtoneManager.getRingtone(mContext, notification);
r.play();
} catch (Exception ex) {
}
}
/** * Play the default alarm tone **@returnMediaPlayer object *@throws Exception
*/
public static void defaultAlarmMediaPlayer(Context mContext) {
try {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
Ringtone r = RingtoneManager.getRingtone(mContext, notification);
r.play();
} catch (Exception ex) {
}
}
}
Copy the code
Register the broadcast instance in the onCreate() method of the mainActivity.class activity.
public class MainActivity extends AppCompatActivity {
// Declare an operation constant string
public static final String ACTION_SERVICE_NEED = "action.ServiceNeed";
// Declare an internal broadcast instance
public ServiceNeedBroadcastReceiver broadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/** * Add flag bits to allow the message to be displayed on the lock screen. In screen lock mode * 2. Unlock * 3. (Optional) Keep the screen on * 4. Open screen * When the Activity starts, it unlocks and displays on the bright screen */
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED // Display in the locked state
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD / / unlock
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON // Keep the screen bright
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); // Open the screen
/** * register the broadcast instance (when initialized) */
IntentFilter filter = new IntentFilter();
// Add an Action to the intent filter (to distinguish the broadcast source, which is equivalent to the broadcast ID)
filter.addAction(ACTION_SERVICE_NEED);
broadcastReceiver = new ServiceNeedBroadcastReceiver();
registerReceiver(broadcastReceiver, filter);
}
Copy the code
4, Service to the broadcast interface to send instructions (about the use of Service, I can see my other blog) code:
public class taskService extends Service {
/** * call startService() callback to start the service */
@Override
public int onStartCommand(Intent intent, int flags, int startId) {/ Send a broadcast message to the Activity interface in the Service class. Intent intentBroadcastReceiver =new Intent();
// Set the intent filter Action (to distinguish the broadcast source, which is equivalent to the broadcast ID)
intentBroadcastReceiver.setAction(MainActivity.ACTION_SERVICE_NEED);
// Add the NEW_TASK flag bit (must be added otherwise message alerts cannot be implemented under lock screen)
intentBroadcastReceiver.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Send unordered broadcast
sendBroadcast(intentBroadcastReceiver);
return super.onStartCommand(intent, flags, startId);
}
/** * Bind to the client of the service via bindService() */
@Override
public IBinder onBind(Intent intent) {
return null; }}Copy the code