You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rjgc/ui/AlarmAlertActivity.java

249 lines
8.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 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.
*/
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;
/**
* 闹钟提醒活动 - 笔记定时提醒功能
*
* 【模块功能】
* 1. 当笔记设置的提醒时间到达时,自动弹出提醒对话框
* 2. 支持在锁屏状态下显示提醒界面(唤醒屏幕)
* 3. 播放系统默认的闹钟铃声提醒用户
* 4. 显示笔记内容摘要最多60个字符
* 5. 提供两种操作选项:
* - "确定":关闭提醒并停止闹钟
* - "查看":跳转到笔记编辑页面查看完整内容(仅屏幕开启时显示)
*
* 【使用场景】
* - 用户为笔记设置了提醒时间后,系统在指定时间触发此活动
* - 无论应用是否在前台运行,都能正常显示提醒
* - 支持锁屏状态下唤醒屏幕并显示提醒
*
* 【技术要点】
* - 使用WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED实现锁屏显示
* - 使用MediaPlayer播放系统闹钟铃声
* - 通过Intent从AlarmReceiver接收笔记ID
* - 实现OnClickListener和OnDismissListener处理用户交互
*
* 【生命周期】
* 1. onCreate: 初始化界面、获取笔记数据、播放闹钟声音
* 2. onClick: 处理用户点击按钮事件
* 3. onDismiss: 对话框关闭时停止闹钟并结束活动
*
* @author MiCode Open Source Community
* @modified 2026-05-07 (Complete Chinese Documentation & Bug Fix)
* @version 1.0
* @see AlarmReceiver 闹钟广播接收器
* @see AlarmInitReceiver 闹钟初始化接收器
* @see NoteEditActivity 笔记编辑活动
*/
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
// 笔记ID
private long mNoteId;
// 笔记内容摘要
private String mSnippet;
// 摘要最大显示长度
private static final int SNIPPET_PREW_MAX_LEN = 60;
// 媒体播放器,用于播放闹钟声音
MediaPlayer mPlayer;
/**
* 活动创建时的初始化方法
* 设置窗口标志、获取笔记数据、显示对话框并播放闹钟声音
*
* @param savedInstanceState 保存的实例状态
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 隐藏标题栏
requestWindowFeature(Window.FEATURE_NO_TITLE);
final Window win = getWindow();
// 允许在锁屏状态下显示窗口
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
// 如果屏幕未开启,添加额外的标志来唤醒屏幕
if (!isScreenOn()) {
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
}
Intent intent = getIntent();
try {
// 从Intent的URI路径中提取笔记ID
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
// 根据笔记ID获取内容摘要
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId);
// 如果摘要过长截取前60个字符并添加省略提示
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) {
// URI格式错误打印异常并退出
e.printStackTrace();
return;
}
mPlayer = new MediaPlayer();
// 验证笔记是否在数据库中可见
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
showActionDialog();
playAlarmSound();
} else {
// 笔记不存在或不可见,直接关闭活动
finish();
}
}
/**
* 检查屏幕是否处于开启状态
*
* @return true表示屏幕已开启false表示屏幕关闭
*/
private boolean isScreenOn() {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
return pm.isScreenOn();
}
/**
* 播放闹钟声音
* 使用系统默认的闹钟铃声,并根据静音模式设置音频流类型
*/
private void playAlarmSound() {
// 获取系统默认的闹钟铃声URI
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
// 获取静音模式下受影响的音频流设置
int silentModeStreams = Settings.System.getInt(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
// 根据静音模式设置选择合适的音频流类型
if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) {
mPlayer.setAudioStreamType(silentModeStreams);
} else {
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
}
try {
mPlayer.setDataSource(this, url);
mPlayer.prepare();
mPlayer.setLooping(true); // 循环播放
mPlayer.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 显示操作对话框
* 显示笔记标题和内容摘要,根据屏幕状态决定是否显示"查看"按钮
*/
private void showActionDialog() {
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setTitle(R.string.app_name);
dialog.setMessage(mSnippet);
dialog.setPositiveButton(R.string.notealert_ok, this);
// 只有在屏幕开启时才显示"查看"按钮
if (isScreenOn()) {
dialog.setNegativeButton(R.string.notealert_enter, this);
}
dialog.show().setOnDismissListener(this);
}
/**
* 处理对话框按钮点击事件
*
* @param dialog 对话框对象
* @param which 被点击的按钮标识
*/
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_NEGATIVE:
// 点击"查看"按钮,跳转到笔记编辑页面
Intent intent = new Intent(this, NoteEditActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_UID, mNoteId);
startActivity(intent);
break;
default:
// 点击"确定"按钮不做额外操作由onDismiss处理
break;
}
}
/**
* 对话框关闭时的回调方法
* 停止闹钟声音并结束当前活动
*
* @param dialog 对话框对象
*/
public void onDismiss(DialogInterface dialog) {
stopAlarmSound();
finish();
}
/**
* 停止闹钟声音并释放媒体播放器资源
* 防止内存泄漏
*/
private void stopAlarmSound() {
if (mPlayer != null) {
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
}
}