记录佩戴耳机时长App开发

移动辅助类App编程项目


基础:掌握Android编程,java程序设计,嵌入式开发

  1. Android编程:学会简单的UI编程,能够设计XML静态界面布局以及动态更新界面,
    熟悉Android四大组件Activity、Service、Broadcast、ContentProvider以及intent消息意图,实现组件之间的通信
  2. java程序设计:面向对象编程,多线程机制,文件字节字符流输入输出流读写文件,接口与多态

开发软件:Android studio x64

软件说明

本软件设计的目的是防止用户沉迷于耳机。首先设定一个提示时间(建议不超过60分钟), 然后点击开启服务,当佩戴耳机达到预定上限时会自动连续播放一段音频以提示用户。拔下耳机,音频外放一次自动关闭,可以选择清零或者设置更长的限制时间关闭提示。为正常使用软件需获取自启动权限,为避免频繁刷新而删除任务,需要使软件锁定在后台。如果用户不需要使用,可以选择卸载或者关闭自启动功能

实现功能

  1. 判断耳机断开与连接(蓝牙耳机或有线耳机)
  2. AlarmService实现定时操作
  3. 软件服务常驻后台
  4. 音效均衡器处理单个音频

源代码

layout_main.xml静态界面布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="example.com.save.MainActivity"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginRight="100sp"
        android:layout_marginEnd="100sp">
        <TextView
            android:textSize="18sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="今日佩戴耳机时长:"/>
        <TextView
            android:textSize="20sp"
            android:text="暂无数据"
            android:id="@+id/tv_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20sp">
        <EditText
            android:inputType="number"
            android:id="@+id/ettv_limit"
            android:hint="请输入提示时间(分钟)"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
        <Button
            android:layout_marginTop="20sp"
            android:layout_below="@+id/ettv_limit"
            android:id="@+id/bt_ok"
            android:text="设定限制时间"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onClick"
            android:layout_centerVertical="true"
            android:layout_centerHorizontal="true"/>
    </RelativeLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginTop="50sp">
        <Button
            android:id="@+id/bt_clear"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="清零"
            android:onClick="onClick"/>
        <Button
            android:id="@+id/bt_read"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="帮助"
            android:onClick="onClick"/>

    </LinearLayout>

    <Button
        android:id="@+id/bt_start"
        android:layout_marginTop="100sp"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="开启计时服务"
        android:onClick="onClick"/>
    <Button
        android:id="@+id/bt_get"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="获取自启动权限"
        android:onClick="onClick"/>

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/bt_sound"
        android:text="声音处理"
        android:onClick="onClick"/>
</LinearLayout>

MainActivity主界面

package example.com.save;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.SystemClock;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Calendar;


public class MainActivity extends AppCompatActivity{
    
    

    private EditText set_time;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        init();
    }
    //点击事件监听
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public void onClick(View view){
    
    
        int id=view.getId();
        switch (id){
    
    
            case R.id.bt_ok:
                if(set_time.getText().toString().equals("")){
    
    
                    Toast.makeText(this,"请输入整数",Toast.LENGTH_SHORT).show();
                }else{
    
    
                    int limit=Integer.valueOf(set_time.getText().toString());
                    FileProcess.writeInternalData(this,"limit.txt",limit*60);
                    Toast.makeText(this,"已设定提示时间为"+set_time.getText().toString()+"分钟",Toast.LENGTH_LONG).show();
                }

                break;
            case R.id.bt_start:
                Intent intent1=new Intent(this,RecordTimeService.class);
                intent1.setAction("android.intent.action.Service_TimeRecord");
                startService(intent1);
                break;
            case R.id.bt_clear:
                FileProcess.writeInternalData(this,"time.txt",0);
                FileProcess.writeInternalData(this,"time2.txt",0);
                int time2=(int)(SystemClock.elapsedRealtime()/1000);
                FileProcess.writeInternalData(this,"lasttime.txt",time2);
                Toast.makeText(this,"已清空计时数据",Toast.LENGTH_SHORT).show();
                break;
            case R.id.bt_read:
                Toast.makeText(this,"使用前需获取自启动权限,然后点击开启服务",Toast.LENGTH_LONG).show();
                break;

            case R.id.bt_get:
                Intent intent=getAutostartSettingIntent(this);
                startActivity(intent);
                break;
            case R.id.bt_sound:
                MainActivity.this.startActivity(new Intent(MainActivity.this,SoundActivity.class));
                break;
            default:
                break;

        }
    }

    /**
     * 初始化界面
     */

    public void init(){
    
    

        setContentView(R.layout.activity_main);
        set_time=(EditText)findViewById(R.id.ettv_limit);
        //开启线程每隔两秒更新一次UI数据
        final TextView tv_time=(TextView)findViewById(R.id.tv_time);
        Handler mTimeHandler = new Handler() {
    
    
            public void handleMessage(android.os.Message msg) {
    
    
                if (msg.what == 0) {
    
    
                    int n=FileProcess.readInternalData(getApplicationContext(),"time.txt")+FileProcess.readInternalData(getApplicationContext(),"time2.txt");
                    String min=Integer.toString(n/60);
                    String sec=Integer.toString(n%60);
                    tv_time.setText(min+"分"+sec+"秒");
                    sendEmptyMessageDelayed(0, 2000);
                }

            }
        };

        mTimeHandler.sendEmptyMessageDelayed(0, 2000);
    }

    public static void startbootService(Context context){
    
    
        Intent intent1=new Intent(context,RecordTimeService.class);
        intent1.setAction("android.intent.action.recordtimeservice");
        context.startService(intent1);
    }
    /**
     * 获取自启动管理页面的Intent
     * 返回自启动管理页面的Intent
     * */
    public static Intent getAutostartSettingIntent(Context context) {
    
    
        ComponentName componentName = null;
        String brand = Build.MANUFACTURER;
        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        switch (brand.toLowerCase()) {
    
    
            case "samsung"://三星
                componentName = new ComponentName("com.samsung.android.sm", "com.samsung.android.sm.app.dashboard.SmartManagerDashBoardActivity");
                break;
            case "huawei"://华为
                //荣耀V8,EMUI 8.0.0,Android 8.0上,以下两者效果一样
                componentName = new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity");
//            componentName = new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity");//目前看是通用的
                break;
            case "xiaomi"://小米
                componentName = new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity");
                break;
            case "vivo"://VIVO
//            componentName = new ComponentName("com.iqoo.secure", "com.iqoo.secure.safaguard.PurviewTabActivity");
                componentName = new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity");
                break;
            case "oppo"://OPPO
//            componentName = new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity");
                componentName = new ComponentName("com.coloros.oppoguardelf", "com.coloros.powermanager.fuelgaue.PowerUsageModelActivity");
                break;
            case "yulong":
            case "360"://360
                componentName = new ComponentName("com.yulong.android.coolsafe", "com.yulong.android.coolsafe.ui.activity.autorun.AutoRunListActivity");
                break;
            case "meizu"://魅族
                componentName = new ComponentName("com.meizu.safe", "com.meizu.safe.permission.SmartBGActivity");
                break;
            case "oneplus"://一加
                componentName = new ComponentName("com.oneplus.security", "com.oneplus.security.chainlaunch.view.ChainLaunchAppListActivity");
                break;
            case "letv"://乐视
                intent.setAction("com.letv.android.permissionautoboot");
            default://其他
                intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
                intent.setData(Uri.fromParts("package", context.getPackageName(), null));
                break;
        }
        intent.setComponent(componentName);
        return intent;
    }

}

RecordTimeService服务

package example.com.save;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Toast;
import android.support.annotation.RequiresApi;


public class RecordTimeService extends Service {
    
    
    // 时钟广播接收器
    private static TIME_TICK_Receiver time_tick_receiver;
    // 耳机广播接收器
    private HeadsetReceiver HeadsetReceiver;
    // 长时间计时任务AlarmManager
    private AlarmManager manager;
    private PendingIntent pi;
    // 音频控制
    private AudioManager audioManager;


    public RecordTimeService() {
    
    
    }
    @Override
    public IBinder onBind(Intent intent) {
    
    
        return null;
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public void onCreate(){
    
    
        super.onCreate();
        register_time_receiver();
        registerHeadsetReceiver(this);
        Intent intent=new Intent(this,MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent pd =PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
        Notification notify=new Notification.Builder(this)
                .setOngoing(true)
                .setPriority(Notification.PRIORITY_MAX)
                .setContentIntent(pd)
                .setContentTitle("监测中")
                .setContentText("亲,注意佩戴耳机时长呦")
                .setSmallIcon(R.drawable.headplug)
                .build();
        startForeground(1,notify);
    }
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    public int onStartCommand(Intent intent, int flags, int startId){
    
    
        //Log.i("service", "启动");
        manager = (AlarmManager) getSystemService(ALARM_SERVICE);
        int three_sec = 3 * 1000;
        long triggerAtTime = SystemClock.elapsedRealtime() + three_sec;
        Intent i = new Intent(this, AlarmReceiver.class);
        pi = PendingIntent.getBroadcast(this, 0, i, 0);
        manager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);

        //aaa.txt中为1则耳机连接,为0则耳机断开
        if (FileProcess.readInternalData(getApplicationContext(), "aaa.txt") == 1) {
    
    
            //这里开辟一条线程,用来执行具体的逻辑操作:
            new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    //Log.i("Service", "线程");
                    int time2=(int)(SystemClock.elapsedRealtime()/1000)
                            - FileProcess.readInternalData(getApplicationContext(),"lasttime.txt");
                    // 持续佩戴耳机时间
                    FileProcess.writeInternalData(getApplicationContext(),"time2.txt",time2);

                    int newTime = FileProcess.readInternalData(getApplicationContext(), "time.txt")
                            + FileProcess.readInternalData(getApplicationContext(),"time2.txt");

                    //判断时长是否超过上限
                    if (newTime >=FileProcess.readInternalData(getApplicationContext(), "limit.txt") ) {
    
    
                        MediaPlayer mPlayer = MediaPlayer.create(getApplicationContext(),R.raw.red);
                        //语音提示
                        try {
    
    
                            if (mPlayer.getCurrentPosition() > 0)
                                mPlayer.seekTo(0);
                            mPlayer.start();
//                                if(!checkIsWired()){
    
    
//                                    mPlayer.release();
//                                }
                        } catch (IllegalStateException e) {
    
    
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
        return super.onStartCommand(intent,flags,startId);
        //系统kill服务自动重启
        // return Service.START_STICKY;
    }

    /**
     * 注册时钟广播接收器
     */
    private void register_time_receiver(){
    
    
        time_tick_receiver=new TIME_TICK_Receiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_TIME_TICK);
        registerReceiver(time_tick_receiver, filter);
    }

    /**
     * 注册耳机断开与连接广播接收器
     * 判定耳机设备连接状态
     */
    public void registerHeadsetReceiver(Service service) {
    
    
        HeadsetReceiver = new HeadsetReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);
        service.registerReceiver(HeadsetReceiver, intentFilter);
        HeadsetReceiver.setOnHeadsetListener(new OnHeadsetListener() {
    
    
            @Override
            public void isHeadsetConnected(boolean connected) {
    
    
                if (connected) {
    
    
                    //Log.i("receiver","耳机已连接");
                    FileProcess.writeInternalData(getApplicationContext(),"aaa.txt",1);

                    int lasttime=(int)(SystemClock.elapsedRealtime()/1000);
                    FileProcess.writeInternalData(getApplicationContext(),"lasttime.txt",lasttime);

                } else {
    
    
                    //Log.i("receiver","耳机断开");
                    FileProcess.writeInternalData(getApplicationContext(),"aaa.txt",0);
                    int newTime=FileProcess.readInternalData(getApplicationContext(),"time.txt")
                            + FileProcess.readInternalData(getApplicationContext(),"time2.txt");
                    FileProcess.writeInternalData(getApplicationContext(), "time.txt", newTime);
                    FileProcess.writeInternalData(getApplicationContext(),"time2.txt",0);
                }
            }
        });
    }



    public void onDestroy(){
    
    
        super.onDestroy();
        //Toast.makeText(getApplicationContext(),"onDestroy",Toast.LENGTH_SHORT).show();
        //Log.i("service","onDestroy");
    }


    //判断设备连接的另一种方法
    private boolean checkIsWired() {
    
    
        audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    
    
            AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
            for (AudioDeviceInfo device : devices) {
    
    
                int deviceType = device.getType();
                if (deviceType == AudioDeviceInfo.TYPE_WIRED_HEADSET
                        || deviceType == AudioDeviceInfo.TYPE_WIRED_HEADPHONES
                        || deviceType == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP
                        || deviceType == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) {
    
    
                    return true;
                }
            }
        } else {
    
    
            return audioManager.isWiredHeadsetOn() || audioManager.isBluetoothScoOn() || audioManager.isBluetoothA2dpOn();
        }
        return false;
    }
}

AlarmReceiver广播接收器

package example.com.save;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class AlarmReceiver extends BroadcastReceiver {
    
    
    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        Intent intent1=new Intent(context,RecordTimeService.class);
        intent1.setAction("android.intent.action.recordtimeservice");
        context.startService(intent1);
        //Log.i("AlarmReceiver","收到");
    }
}

FileProcess静态方法

package example.com.save;

/**
 * 内部文件文件读写
 */

import android.content.Context;
import android.icu.util.Calendar;
import android.os.Build;
import android.support.annotation.RequiresApi;

import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.nio.ByteBuffer;


public class FileProcess {
    
    

    //写入文件
    public static boolean writeInternalData(Context context, String strPath, int intTxt) {
    
    
        FileOutputStream fos;
        try{
    
    
            fos=context.openFileOutput(strPath,0);
            try{
    
    
                String strTxt=Integer.toString(intTxt);
                fos.write(strTxt.getBytes());
                return true;
            }catch (IOException e){
    
    
                e.printStackTrace();
                return false;
            }
        }catch (FileNotFoundException e){
    
    
            e.printStackTrace();
            return false;
        }
    }

    //读取文件
    public static int readInternalData(Context context, String strPath){
    
    
        FileInputStream fis ;
        byte[] buffer;
        try{
    
    
            fis=context.openFileInput(strPath);
            try{
    
    
                buffer=new byte[fis.available()];
                fis.read(buffer);
                String file_str=new String(buffer);
                int number=Integer.valueOf(file_str);
                return  number;
            }catch (IOException e){
    
    
                e.printStackTrace();
                return 0;
            }
        }catch (FileNotFoundException e){
    
    
            e.printStackTrace();
            return 0;
        }
    }
}

OnHeadsetListener接口(interface)

package example.com.save;

/**
 * 耳机断开与连接接口
 * true为连接,false为断开
 */

public interface OnHeadsetListener {
    
    
    void isHeadsetConnected(boolean connected);
}

HeadsetReceiver耳机广播接收器

package example.com.save;
/**
 * 耳机连接状态广播接收器
 */

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class HeadsetReceiver extends BroadcastReceiver {
    
    
    private OnHeadsetListener onHeadsetListener;

    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        String action = intent.getAction();
        //蓝牙耳机
        if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
    
    
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
            int state = adapter.getProfileConnectionState(BluetoothProfile.HEADSET);
            if (BluetoothProfile.STATE_CONNECTED == state) {
    
    
                onHeadsetListener.isHeadsetConnected(true);
            }
            if (BluetoothProfile.STATE_CONNECTED == state) {
    
    
                onHeadsetListener.isHeadsetConnected(false);
            }
        }
        //有线耳机
        else if (Intent.ACTION_HEADSET_PLUG.equals(action)) {
    
    
            if (intent.hasExtra("state")) {
    
    
                int state = intent.getIntExtra("state", 0);
                if (state == 1) {
    
    
                    //插入耳机
                    onHeadsetListener.isHeadsetConnected(true);
                } else if (state == 0) {
    
    
                    //拔出耳机
                    onHeadsetListener.isHeadsetConnected(false);
                }
            }
        }
    }
    public void setOnHeadsetListener(OnHeadsetListener onHeadsetListener) {
    
    
        this.onHeadsetListener = onHeadsetListener;
    }
}

BootReceiver开机广播接收器

package example.com.save;

/**
 * 开机启动的广播接收器
 */

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class BootReceiver extends BroadcastReceiver {
    
    
    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        //Intent i=new Intent(context,MainActivity.class);
        //i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        //context.startService(i);
        MainActivity.startbootService(context);
    }
}

TIME_TICK_Receiver广播接收器

package example.com.save;

/**
 * 开机启动的广播接收器
 */

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class BootReceiver extends BroadcastReceiver {
    
    
    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        //Intent i=new Intent(context,MainActivity.class);
        //i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        //context.startService(i);
        MainActivity.startbootService(context);
    }
}

SoundActivity动态界面

package example.com.save;


import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.audiofx.BassBoost;
import android.media.audiofx.Equalizer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;


import java.io.IOException;


public class SoundActivity extends AppCompatActivity {
    
    
    // 声明音乐文件名
    private String music="平凡之路.mp3";
    // 文件读取
    AssetManager am;
    private boolean flag=true;
    // 定义播放声音的MediaPlayer
    private MediaPlayer mPlayer;
    // 定义系统的均衡器
    private Equalizer mEqualizer;
    // 定义系统的重低音控制器
    private BassBoost mBass;
    // 定义线性布局
    private LinearLayout layout;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        //Log.i("SoundActivity","跳转");
        //设置音频流 - STREAM_MUSIC:音乐回放即媒体音量
        setVolumeControlStream(AudioManager.STREAM_MUSIC);
        layout = new LinearLayout(this);//代码创建布局
        layout.setOrientation(LinearLayout.VERTICAL);//设置为线性布局-上下排列
        setContentView(layout);//将布局加入到 Activity
        //mPlayer = MediaPlayer.create(getApplicationContext(), R.raw.red);
        am = this.getAssets();
        mPlayer=new MediaPlayer();
        prepareMusic(music);

        //音乐播放完毕监听器
        mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
    
    
            @Override
            public void onCompletion(MediaPlayer mp) {
    
    
                prepareMusic(music);
                mPlayer.start();
            }
        });

        // 初始化均衡控制器
        setupEqualizer();
        // 初始化重低音控制器
        setupBassBoost();
        // 初始化按钮
        setButton();

        //mPlayer.start();
    }
    private void setupEqualizer()
    {
    
    
        // 每个MediaPlayer都有自己独一无二的SessionId
        // 以MediaPlayer的AudioSessionId创建Equalizer
        // 相当于设置Equalizer负责控制该MediaPlayer
        mEqualizer = new Equalizer(0, mPlayer.getAudioSessionId());

        // 启用均衡控制效果
        mEqualizer.setEnabled(true);

        TextView eqTitle = new TextView(this);
        eqTitle.setText("均衡器:");
        layout.addView(eqTitle);
        // 获取均衡控制器支持最小值和最大值
        final short minEQLevel = mEqualizer.getBandLevelRange()[0];//第一个下标为最低的限度范围
        short maxEQLevel = mEqualizer.getBandLevelRange()[1];  // 第二个下标为最高的限度范围
        // 获取均衡控制器支持的全部频率
        short brands = mEqualizer.getNumberOfBands();
        for (short i = 0; i < brands; i++) {
    
    
            TextView eqTextView = new TextView(this);
            // 创建一个TextView。用于显示频率
            eqTextView.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT));
            eqTextView.setGravity(Gravity.CENTER_HORIZONTAL);
            // 设置该均衡控制器的频率
            eqTextView.setText((mEqualizer.getCenterFreq(i) / 1000) + " Hz");
            layout.addView(eqTextView);
            // 创建一个水平排列组件的LinearLayout
            LinearLayout tmpLayout = new LinearLayout(this);
            tmpLayout.setOrientation(LinearLayout.HORIZONTAL);
            // 创建显示均衡控制器最小值的TextView
            TextView minDbTextView = new TextView(this);
            minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT));
            // 显示均衡控制器的最小值
            minDbTextView.setText((minEQLevel / 100) + " dB");
            // 创建显示均衡控制器最大值的TextView
            TextView maxDbTextView = new TextView(this);
            maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT));
            // 显示均衡控制器的最大值
            maxDbTextView.setText((maxEQLevel / 100) + " dB");
            LinearLayout.LayoutParams layoutParams = new
                    LinearLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
            layoutParams.weight = 1;
            // 定义SeekBar做为调整工具
            SeekBar bar = new SeekBar(this);
            bar.setLayoutParams(layoutParams);
            bar.setMax(maxEQLevel - minEQLevel);
            bar.setProgress(mEqualizer.getBandLevel(i));
            final short brand = i;
            // 为SeekBar的拖动事件设置事件监听器
            bar.setOnSeekBarChangeListener(new SeekBar
                    .OnSeekBarChangeListener()
            {
    
    
                @Override
                public void onProgressChanged(SeekBar seekBar,
                                              int progress, boolean fromUser)
                {
    
    
                    // 设置该频率的均衡值
                    mEqualizer.setBandLevel(brand,
                            (short) (progress + minEQLevel));
                }
                @Override
                public void onStartTrackingTouch(SeekBar seekBar)
                {
    
    
                }
                @Override
                public void onStopTrackingTouch(SeekBar seekBar)
                {
    
    
                }
            });
            // 使用水平排列组件的LinearLayout“盛装”3个组件
            tmpLayout.addView(minDbTextView);
            tmpLayout.addView(bar);
            tmpLayout.addView(maxDbTextView);
            // 将水平排列组件的LinearLayout加入到myLayout容器中
            layout.addView(tmpLayout);
        }
    }

    /**
     * 初始化重低音控制器
     */
    private void setupBassBoost()
    {
    
    
        // 以MediaPlayer的AudioSessionId创建BassBoost
        // 相当于设置BassBoost负责控制该MediaPlayer
        mBass = new BassBoost(0, mPlayer.getAudioSessionId());
        // 设置启用重低音效果
        mBass.setEnabled(true);
        TextView bbTitle = new TextView(this);
        bbTitle.setText("重低音:");
        layout.addView(bbTitle);
        // 使用SeekBar做为重低音的调整工具
        SeekBar bar = new SeekBar(this);
        // 重低音的范围为0~1000
        bar.setMax(1000);
        bar.setProgress(0);
        // 为SeekBar的拖动事件设置事件监听器
        bar.setOnSeekBarChangeListener(new SeekBar
                .OnSeekBarChangeListener()
        {
    
    
            @Override
            public void onProgressChanged(SeekBar seekBar,int progress,boolean fromUser)
            {
    
    
                // 设置重低音的强度
                mBass.setStrength((short) progress);
            }
            @Override
            public void onStartTrackingTouch(SeekBar seekBar)
            {
    
    
            }
            @Override
            public void onStopTrackingTouch(SeekBar seekBar)
            {
    
    
            }
        });
        layout.addView(bar);
    }

    /**
     * 初始化暂停和播放按钮
     */
    private void setButton(){
    
    
        final ImageButton btnPlay=new ImageButton(this);
        btnPlay.setImageResource(R.drawable.play);
        btnPlay.setOnClickListener(new View.OnClickListener(){
    
    
            @Override
            public void onClick(View v){
    
    
                if(flag){
    
    
                    btnPlay.setImageResource(R.drawable.pause);
                    //mPlayer = MediaPlayer.create(getApplicationContext(), R.raw.red);
                    prepareMusic(music);
                    mPlayer.start();
                    flag=false;
                }else{
    
    
                    btnPlay.setImageResource(R.drawable.play);
                    //mPlayer.release();
                    mPlayer.stop();
                    flag=true;
                }

            }
        });
        layout.addView(btnPlay);

    }

    /**
     * 返回键销毁界面和音频,避免退出造成空指针错误
     */
    public boolean onKeyDown(int keyCode, KeyEvent event) {
    
    
        switch (keyCode) {
    
    
            case KeyEvent.KEYCODE_BACK:
                SoundActivity.this.finish();
                //mPlayer.release();
                mPlayer.stop();
        }
        return super.onKeyDown(keyCode,event);
    }

    /**
    * 准备播放音乐
    */
    private void prepareMusic(String music){
    
    
        try{
    
    
            AssetFileDescriptor afd = am.openFd(music);
            mPlayer.reset();
            mPlayer.setDataSource(afd.getFileDescriptor()
                    ,afd.getStartOffset()
                    ,afd.getLength());
            mPlayer.prepare();
        }catch (IOException e){
    
    
            e.printStackTrace();
        }
    }

    public void onDestroy(){
    
    
        super.onDestroy();
    }
}

AndroidManifest.xml清单文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="example.com.save">

    <!--申请权限-->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

    <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>
        <activity android:name=".SoundActivity"/>

        <service
            android:name=".RecordTimeService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.recordtimeservice" />
            </intent-filter>
        </service>

        <receiver
            android:name=".BootReceiver"
            android:enabled="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
        <receiver
            android:name=".HeadsetReceiver"
            android:enabled="true"
            android:exported="true" />
        <receiver
            android:name=".AlarmReceiver" />
        <receiver
            android:name=".TIME_TICK_Receiver"/>

    </application>

</manifest>

缺点

  1. 频繁读取和写入文件可能造成内存泄露甚至削减存储卡的寿命
  2. 常驻后台服务降低手机性能,非正常消耗手机电量

猜你喜欢

转载自blog.csdn.net/qq_48211069/article/details/118711481
今日推荐