|
|
|
@ -0,0 +1,182 @@
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// 220340038 毛彦翔 2024/4/14
|
|
|
|
|
|
|
|
|
|
package net.micode.notes.ui;
|
|
|
|
|
|
|
|
|
|
import android.app.Activity;
|
|
|
|
|
import android.app.AlertDialog;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.DialogInterface;
|
|
|
|
|
import android.content.DialogInterface.OnClickListener;
|
|
|
|
|
import android.content.DialogInterface.OnDismissListener;
|
|
|
|
|
import android.content.Intent;
|
|
|
|
|
import android.media.AudioManager;
|
|
|
|
|
import android.media.MediaPlayer;
|
|
|
|
|
import android.media.RingtoneManager;
|
|
|
|
|
import android.net.Uri;
|
|
|
|
|
import android.os.Bundle;
|
|
|
|
|
import android.os.PowerManager;
|
|
|
|
|
import android.provider.Settings;
|
|
|
|
|
import android.view.Window;
|
|
|
|
|
import android.view.WindowManager;
|
|
|
|
|
|
|
|
|
|
import net.micode.notes.R;
|
|
|
|
|
import net.micode.notes.data.Notes;
|
|
|
|
|
import net.micode.notes.tool.DataUtils;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
|
|
|
|
|
private long mNoteId; //便签在库中的检索ID
|
|
|
|
|
private String mSnippet; //便签提醒时显示的文本
|
|
|
|
|
private static final int SNIPPET_PREW_MAX_LEN = 60;
|
|
|
|
|
MediaPlayer mPlayer;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
|
super.onCreate(savedInstanceState);//通过savedInstanceState获取状态信息
|
|
|
|
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
|
|
|
//通过requestWindowFeature指定活动窗口的特性(无标题)
|
|
|
|
|
|
|
|
|
|
final Window win = getWindow();
|
|
|
|
|
/*
|
|
|
|
|
*获取当前活动的window对象,并赋值给名为win的final变量
|
|
|
|
|
*由于final变量 在赋值后不能再改变,
|
|
|
|
|
*可以确保后续引用该变量时不会被意外修改 提高代码的可维护性
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
|
|
|
|
|
//使window对象win可以在锁屏后仍然显示 即可以覆盖在锁屏界面之上
|
|
|
|
|
|
|
|
|
|
if (!isScreenOn()) { //检查屏幕是否开启
|
|
|
|
|
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
|
|
|
|
//保持屏幕唤醒 防止自动息屏
|
|
|
|
|
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
|
|
|
|
|
//唤醒屏幕并显示窗口 不明白与66行保持屏幕唤醒的区别
|
|
|
|
|
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
|
|
|
|
|
//允许屏幕在保持唤醒的情况下手动锁定屏幕 猜测与66行FLAG_KEEP_SCREEN_ON有关
|
|
|
|
|
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
|
|
|
|
|
//控制边距 确保布局和内容正常显示
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Intent intent = getIntent();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
|
|
|
|
|
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId);
|
|
|
|
|
//通过检索ID从库中获取便签内容
|
|
|
|
|
mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0,
|
|
|
|
|
SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info)
|
|
|
|
|
: mSnippet;
|
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
return;
|
|
|
|
|
}//捕获异常信息 打印异常堆栈并直接返回 避免因错误信息导致程序崩溃
|
|
|
|
|
|
|
|
|
|
mPlayer = new MediaPlayer(); //创建一个MediaPlayer对象用于播放音频
|
|
|
|
|
if (DataUtils.visibleInNoteDatabase/*便签是否可见*/(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
|
|
|
|
|
showActionDialog(); //笔记存在可见则显示操作对话框
|
|
|
|
|
playAlarmSound(); //同时播放警示音
|
|
|
|
|
} else {
|
|
|
|
|
finish(); //笔记不存在或不可见则调用finish函数结束当前活动 关闭页面
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean isScreenOn() {
|
|
|
|
|
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
|
|
|
|
return pm.isScreenOn();
|
|
|
|
|
} //一个通过访问系统电源管理服务检查屏幕是否开启 并返回布尔值的私有方法
|
|
|
|
|
|
|
|
|
|
private void playAlarmSound() {
|
|
|
|
|
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
|
|
|
|
|
//获取当前默认铃声的uri并存储在Uri类型的变量url中 Uri是什么类型?写完再查
|
|
|
|
|
int silentModeStreams = Settings.System.getInt(getContentResolver(),
|
|
|
|
|
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
|
|
|
|
|
//从系统设置中获取当前静音模式下受铃声模式影响的流的信息,并存储在一个整数变量中
|
|
|
|
|
//作用是什么?没想明白
|
|
|
|
|
if ((silentModeStreams/*处于静音模式*/ & (1 << AudioManager.STREAM_ALARM)) != 0) {
|
|
|
|
|
mPlayer.setAudioStreamType(silentModeStreams);
|
|
|
|
|
/*这下看懂了
|
|
|
|
|
*使用位运算判断静音模式下是否受到铃声模式影响
|
|
|
|
|
*与运算结果不为0则表示静音模式下受到铃声模式影响
|
|
|
|
|
*受铃声模式影响则直接调用setAudioStreamType(silentModeStreams)设置音频流类型
|
|
|
|
|
*/
|
|
|
|
|
} else {
|
|
|
|
|
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
|
|
|
|
|
} //否则使用AudioManager.STREAM_ALARM作为银趴留类型 总之 确保播放的铃声会受系统静音模式控制
|
|
|
|
|
try {
|
|
|
|
|
mPlayer.setDataSource(this, url);
|
|
|
|
|
mPlayer.prepare();
|
|
|
|
|
mPlayer.setLooping(true);
|
|
|
|
|
mPlayer.start();
|
|
|
|
|
//设置MediaPlayer的数据源 准备播放铃声并循环播放 不一一注释了
|
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
|
// TODO Auto-generated catch block
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
} catch (SecurityException e) {
|
|
|
|
|
// TODO Auto-generated catch block
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
} catch (IllegalStateException e) {
|
|
|
|
|
// TODO Auto-generated catch block
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
// TODO Auto-generated catch block
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
//用于捕获可能抛出的异常 发生以上异常则打印异常信息并继续执行
|
|
|
|
|
//看不懂上面的注释 查找后发现是IDE自动生成的catch块
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void showActionDialog() { //显示操作对话框的私有方法
|
|
|
|
|
AlertDialog.Builder dialog = new AlertDialog.Builder(this); //构建对话框 在当前活动窗口中显示
|
|
|
|
|
dialog.setTitle(R.string.app_name); //设置对话框标题 文本来自app_name 这是什么
|
|
|
|
|
dialog.setMessage(mSnippet); //对话框的内容 mSnippet在第46行被定义 这是什么来着
|
|
|
|
|
dialog.setPositiveButton(R.string.notealert_ok, this); //某个按钮?没懂 positive按钮是什么
|
|
|
|
|
if (isScreenOn()) {
|
|
|
|
|
dialog.setNegativeButton(R.string.notealert_enter, this); //negative按钮又是什么 晕了 这俩玩意的功能写在哪了
|
|
|
|
|
}
|
|
|
|
|
dialog.show().setOnDismissListener(this); //头好痛 要长脑子了
|
|
|
|
|
}
|
|
|
|
|
DialogInterface.OnClickListener
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) { //对话框被点击时调用 DialogInterface.OnClickListener接口的实现
|
|
|
|
|
switch (which) { // 用Switch分值判断哪个按钮被点击了 为什么不用if-else呢
|
|
|
|
|
case DialogInterface.BUTTON_NEGATIVE: //negative按钮被按了!
|
|
|
|
|
Intent intent = new Intent(this, NoteEditActivity.class); //新建intent对象 调用NoteEditActivity类
|
|
|
|
|
intent.setAction(Intent.ACTION_VIEW); //把当前活动状态设置为action_view
|
|
|
|
|
intent.putExtra(Intent.EXTRA_UID, mNoteId); //加了个什么东西 键为EXTRA_UID,值为mNoteID 检索ID?是把这对键值赋给新建的便签吗
|
|
|
|
|
startActivity(intent); //启动。
|
|
|
|
|
break;
|
|
|
|
|
default: //按的不是negative按钮则停止活动 为什么startActivity按的是negative按钮不是positive按钮
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void onDismiss(DialogInterface dialog) {
|
|
|
|
|
stopAlarmSound();
|
|
|
|
|
finish();
|
|
|
|
|
} //最简单的一集 对话框消失则调用这两个函数 停止播放警示音并关闭当前活动
|
|
|
|
|
|
|
|
|
|
private void stopAlarmSound() {
|
|
|
|
|
if (mPlayer != null) { //就爱你差对象是否为空 是为了防止空指针吗
|
|
|
|
|
mPlayer.stop();
|
|
|
|
|
mPlayer.release(); //释放MediaPlayer使用的系统资源 避免资源浪费
|
|
|
|
|
mPlayer = null; //将mPlayer设置为空 回收内存空间防止泄露
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|