效果:这是一个吹蜡烛锁屏的demo,蜡烛是我放置的两张图片,一张为亮着的,一张为熄灭的。我们对着屏幕吹,蜡烛就会熄灭,并且实现锁屏。
原理:利用麦克风分辨当前声音的分贝,当分贝过大的时候,实现图片置换(亮->灭),然后锁屏。
首先AndroidManifest.xml权限配置:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.lijunhua.candleclosescreen">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".MyDeviceAdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN" >
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/my_device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
</application>
</manifest>
然后是activity_main.xml,drawble中放置蜡烛图片:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<ImageView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/candle" />
</LinearLayout>
然后MainActivity.java:
package com.example.lijunhua.candleclosescreen;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
public class MainActivity extends AppCompatActivity {
private ImageVew imageView;
private MicroPhoneThread microPhone = new MicroPhoneThread(); //线程用于实时录制周围声音
public boolean istrue = true;
private MediaRecorder mARecorder; //麦克风控制
private File mAudiofile,mSampleDir; //录音文件保存
private MHandler mHandler = new MHandler();
class MHandler extends Handler{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.arg1){
case 1:
imageView.setBackgroundResource(R.drawable.candlethree);//换成熄灭的蜡烛图片
//延迟实现
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//todo
//锁屏实现
lockScreen();
}
}, 1000);
break;
}
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView=findViewById(R.id.imageview);
}
@Override
protected void onStart() {
super.onStart();
//录音获取麦克风声音
mARecorder = new MediaRecorder(); //声音录制
mARecorder.setAudioSource(MediaRecorder.AudioSource.MIC); //录制的音源为麦克风
mARecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR); //设置音频文件的编码
mARecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); //设置audio格式
try{
mSampleDir = Environment.getExternalStorageDirectory(); //获取手机内存路径
//用IM+系统当前时间为文件名建立.amr的文件,文件路径为mSampleDir
mAudiofile = File.createTempFile("IM" + System.currentTimeMillis(),".amr",mSampleDir);
} catch (IOException e) {
Log.e("IMMESSAGE","sdcard access error");
}
mARecorder.setOutputFile(mAudiofile.getAbsolutePath()); //设置路径
try{
mARecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
mARecorder.start();
microPhone.start();
}
class MicroPhoneThread extends Thread{ //测试当前分贝值通知UI修改
final float minAngle = (float) Math.PI * 4 / 11;
float angle;
@Override
public void run() {
while(istrue){
angle = 100 * minAngle * mARecorder.getMaxAmplitude() / 32768;
if(angle > 100){
angle = 100;
}
if(angle>50)
{
Message message = new Message();
message.arg1 = 1;
//mHandler.sendMessage(mHandler.obtainMessage(1, p));
mHandler.sendMessage(message);
}
//构造方法的字符格式这里如果小数不足2位,会已0补足
DecimalFormat decimalFormat = new DecimalFormat("0.00");
String p = decimalFormat.format(angle);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//锁屏
private void lockScreen()
{
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName componentName = new ComponentName(this, MyDeviceAdminReceiver.class);
boolean active = dpm.isAdminActive(componentName);
if (!active) {
// http://developer.android.com/reference/android/app/admin/DeviceAdminReceiver.html
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, componentName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "我自己的LockNow");
startActivityForResult(intent, 0);
}
try {
dpm.lockNow();
}
catch (final Exception ex)
{
}
android.os.Process.killProcess(android.os.Process.myPid());
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (0 == requestCode) {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
然后建立一个java类:
package com.example.lijunhua.candleclosescreen;
import android.app.admin.DeviceAdminReceiver;
public class MyDeviceAdminReceiver extends DeviceAdminReceiver {
}
然后在res中建立一个xml文件夹,再新建->XML resource file:
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<force-lock />
</uses-policies>
</device-admin>
如果安卓版本6.0以上需要动态申请权限,新建一个java类,并且在MainAticity的OnCreate中调用类的方法:
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
public class JurisdictionApply {
//要申请的权限
private static String[] PERMISSIONS = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.RECORD_AUDIO //录音权限
};
/*
* 申请权限*/
public static boolean isGrantExternalRW(Activity activity, int requestCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int writeStoragePermission = activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
int readStoragePermission = activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
int recorderPermission = activity.checkSelfPermission(Manifest.permission.RECORD_AUDIO);
//检测是否有权限,如果没有权限,就需要申请
if (writeStoragePermission != PackageManager.PERMISSION_GRANTED ||
readStoragePermission != PackageManager.PERMISSION_GRANTED ||
recorderPermission != PackageManager.PERMISSION_GRANTED) {
//申请权限
activity.requestPermissions(PERMISSIONS, requestCode);
//返回false。说明没有授权
return false;
}
}
//说明已经授权
return true;
}
}
最后,运行。