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.
Notes/src/ui/AlarmAlertActivity.java

369 lines
16 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.app.PendingIntent;
import android.app.AlarmManager;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.database.Cursor;
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.util.Log;
import android.view.Window;
import android.view.WindowManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.DataUtils;
import java.io.IOException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Calendar;
//继承Activity //承诺实现clickdismiss接口不继承功能
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
private static final String TAG = "AlarmAlertActivity";
private long mNoteId;
private String mSnippet;
private static final int SNIPPET_PREW_MAX_LEN = 60;
MediaPlayer mPlayer;
@Override //创建闹钟行为
protected void onCreate(Bundle savedInstanceState) {
//调用其父类Activity的onCreate方法来实现对界面的图画绘制工作。
super.onCreate(savedInstanceState);
//onSaveInstanceState()来保存当前activity的状态信息
requestWindowFeature(Window.FEATURE_NO_TITLE);
//final类似stactic获得窗口对象
final Window win = getWindow();
//为窗口添加各种标志flags从而改变窗口的行为和外观
//屏幕锁定时显示窗口,便于锁屏时启动闹钟
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
//LayoutParams 布局参数,规定子视图如何放置
if (!isScreenOn()) {//不锁平时
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON//当这个window对用户是可见状态,则保持设备屏幕不关闭且不变暗
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON//当window被添加或者显示,系统会点亮屏幕,
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON//允许在屏幕开启的时候锁定屏幕
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);//插入window的矩形大小,来确保内容不会被装饰物(如状态栏)掩盖
}
Intent intent = getIntent();
try { //传递到当前组件的 URI 数据截取Uri内的字符串的第二个“/”右边的字符及id
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
//根据ID从数据库中获取标签的内容
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId);
//判断是否超过最大长度,超过执行截取操作
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();
//如果不在回收站就显示文字并发出声音
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
int isHabit = intent.getIntExtra("habit_alarm", 0);
if (isHabit == 1) {
showHabitDialog(intent);
} else {
showActionDialog();
}
playAlarmSound();
} else {
finish();
}
}
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) {
// 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();
}
}
private void showActionDialog() {
//AlertDialog.Builder是对话框组件用于显示信息
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setTitle(R.string.app_name);
dialog.setMessage(mSnippet);
dialog.setPositiveButton(R.string.notealert_ok, this); //setPositive/Negative/NeutralButton()设置:确定,取消,中立按钮;
if (isScreenOn()) {
dialog.setNegativeButton(R.string.notealert_enter, this);
}
dialog.show().setOnDismissListener(this);
}
// Habit specific dialog with actions: complete, snooze, skip, abandon
private void showHabitDialog(Intent intent) {
View v = getLayoutInflater().inflate(R.layout.habit_alert_dialog, null);
TextView tvTitle = (TextView) v.findViewById(R.id.habit_alert_title);
TextView tvSnippet = (TextView) v.findViewById(R.id.habit_alert_snippet);
final Button btnComplete = (Button) v.findViewById(R.id.habit_btn_complete);
final Button btnSnooze10 = (Button) v.findViewById(R.id.habit_btn_snooze10);
final Button btnSnooze30 = (Button) v.findViewById(R.id.habit_btn_snooze30);
final Button btnSkip = (Button) v.findViewById(R.id.habit_btn_skip);
final Button btnAbandon = (Button) v.findViewById(R.id.habit_btn_abandon);
tvTitle.setText(getString(R.string.app_name));
tvSnippet.setText(mSnippet);
final AlertDialog d = new AlertDialog.Builder(this)
.setView(v)
.create();
btnComplete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
recordHabitHistory(mNoteId, "completed", "");
Toast.makeText(AlarmAlertActivity.this, R.string.habit_record_complete, Toast.LENGTH_SHORT).show();
d.dismiss();
}
});
btnSnooze10.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
scheduleSnooze(mNoteId, 10);
Toast.makeText(AlarmAlertActivity.this, R.string.habit_snoozed, Toast.LENGTH_SHORT).show();
d.dismiss();
}
});
btnSnooze30.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
scheduleSnooze(mNoteId, 30);
Toast.makeText(AlarmAlertActivity.this, R.string.habit_snoozed, Toast.LENGTH_SHORT).show();
d.dismiss();
}
});
btnSkip.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showSkipReasonDialog();
// 不要立即关闭对话框,让用户选择原因
}
});
btnAbandon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
abandonHabit(mNoteId);
Toast.makeText(AlarmAlertActivity.this, R.string.habit_abandoned, Toast.LENGTH_SHORT).show();
d.dismiss();
}
});
d.setOnDismissListener(this);
d.show();
}
private void showSkipReasonDialog() {
final String[] reasons = new String[] { getString(R.string.skip_reason_busy),
getString(R.string.skip_reason_sick), getString(R.string.skip_reason_other) };
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.setTitle(R.string.habit_skip_title);
b.setItems(reasons, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String reason = reasons[which];
recordHabitHistory(mNoteId, "skipped", reason);
Toast.makeText(AlarmAlertActivity.this, R.string.habit_record_skipped, Toast.LENGTH_SHORT).show();
// 选择原因后关闭主对话框
dialog.dismiss();
finish();
}
});
b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
b.show();
}
private void scheduleSnooze(long noteId, int minutes) {
try {
Intent intent = new Intent(this, AlarmReceiver.class);
intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId));
intent.putExtra("habit_alarm", 1);
int req = (int) (noteId ^ 0x100000) + minutes; // unique-ish
PendingIntent pi = PendingIntent.getBroadcast(this, req, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
long trigger = System.currentTimeMillis() + minutes * 60 * 1000L;
am.set(AlarmManager.RTC_WAKEUP, trigger, pi);
} catch (Exception e) {
Log.e(TAG, "Schedule snooze error", e);
}
}
private void abandonHabit(long noteId) {
try {
ContentValues values = new ContentValues();
values.put(Notes.NoteColumns.IS_HABIT, 0);
values.put(Notes.NoteColumns.HABIT_CONFIG, "");
getContentResolver().update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), values, null, null);
// cancel repeating alarm
Intent intent = new Intent(this, AlarmReceiver.class);
intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId));
intent.putExtra("habit_alarm", 1);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.cancel(pi);
} catch (Exception e) {
Log.e(TAG, "Abandon habit error", e);
}
}
// Record history into habit_config.history (append object {date,status,reason})
private void recordHabitHistory(long noteId, String status, String reason) {
try {
Uri uri = ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId);
Cursor c = getContentResolver().query(uri, new String[]{Notes.NoteColumns.HABIT_CONFIG}, null, null, null);
String cfg = "";
if (c != null) {
if (c.moveToFirst()) cfg = c.getString(0);
c.close();
}
JSONObject jo = cfg != null && cfg.length() > 0 ? new JSONObject(cfg) : new JSONObject();
JSONArray history = jo.has("history") ? jo.getJSONArray("history") : new JSONArray();
// 获取当前时间戳
long recordTime = System.currentTimeMillis();
// 创建新记录
JSONObject newEntry = new JSONObject();
newEntry.put("date", recordTime);
newEntry.put("status", status);
newEntry.put("reason", reason == null ? "" : reason);
// 检查是否已经存在该日期的记录,如果有则替换
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault());
String recordKey = sdf.format(new java.util.Date(recordTime));
boolean foundRecord = false;
for (int i = 0; i < history.length(); i++) {
JSONObject entry = history.getJSONObject(i);
long entryDate = entry.optLong("date", 0);
String entryKey = sdf.format(new java.util.Date(entryDate));
if (recordKey.equals(entryKey)) {
// 替换该日期的记录
history.put(i, newEntry);
foundRecord = true;
break;
}
}
// 如果没有该日期的记录,添加新记录
if (!foundRecord) {
history.put(newEntry);
}
jo.put("history", history);
ContentValues values = new ContentValues();
values.put(Notes.NoteColumns.HABIT_CONFIG, jo.toString());
getContentResolver().update(uri, values, null, null);
// 通知数据变化,以便日历视图刷新
getContentResolver().notifyChange(uri, null);
} catch (JSONException e) {
Log.e(TAG, "Record habit history json error", e);
}
}
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);//向目标页面传递笔记的ID
startActivity(intent);//触发页面跳转
break;
default:
break;
}
}
//取消监听后操作
public void onDismiss(DialogInterface dialog) {
stopAlarmSound();
finish();
}
//取消声音
private void stopAlarmSound() {
if (mPlayer != null) {
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
}
}