Compare commits

...

10 Commits

@ -0,0 +1,162 @@
/*
* 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;
/*
author:
2023-4-12
*/
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
private long mNoteId;
private String mSnippet;
private static final int SNIPPET_PREW_MAX_LEN = 60;
MediaPlayer mPlayer;
@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//在锁定状态下唤醒屏幕。如果该标志被设置,则当 Activity 启动时,系统将唤醒设备并点亮屏幕。
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON//允许在屏幕常亮时锁定设备。
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);//允许布局扩展到屏幕装饰区域(例如状态栏)之下。
}
Intent intent = getIntent();//获取页面
try {
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));//找到是否有对应的NoteId
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)) {//如果存在对应的便签
showActionDialog();//发出对话框
playAlarmSound();//发出声音
} else {
finish();
}
}
private boolean isScreenOn() {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
return pm.isScreenOn();
}
private void playAlarmSound() {
//获取系统中当前默认的闹钟铃声所对应的 Uri并将其赋值给 url 变量
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
//获取当前系统中哪些音频流会受到静音模式的影响
int silentModeStreams = Settings.System.getInt(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
//如果STREAM_ALARM受到影响那么就将音频流形式设置为silentModeStreams
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 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);//执行相关的动作
}
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:
break;
}
}
public void onDismiss(DialogInterface dialog) {
stopAlarmSound();//关闭闹钟铃声
finish();//该页面结束
}
private void stopAlarmSound() {
if (mPlayer != null) {//如果该播放器存在
mPlayer.stop();//停下
mPlayer.release();//释放资源
mPlayer = null;
}
}
}

@ -0,0 +1,70 @@
/*
* 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.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
/*
Author:
Data:2023-4-12
*/
public class AlarmInitReceiver extends BroadcastReceiver {
private static final String [] PROJECTION = new String [] {
NoteColumns.ID,
NoteColumns.ALERTED_DATE
};
private static final int COLUMN_ID = 0;
private static final int COLUMN_ALERTED_DATE = 1;
@Override
public void onReceive(Context context, Intent intent) {
long currentDate = System.currentTimeMillis();//找到目前的时间段
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,
new String[] { String.valueOf(currentDate) },
null);//筛选出来那些提醒时间大于当前时间并且类型是便签类型的
if (c != null) {
if (c.moveToFirst()) {//如果下一个数据存在的话
do {
long alertDate = c.getLong(COLUMN_ALERTED_DATE);//获取当前数据的日期
Intent sender = new Intent(context, AlarmReceiver.class);//获取一个新的页面
sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID)));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0);
AlarmManager alermManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent);//采用系统实时时钟RTC闹钟
//当闹钟到达alertDate时唤醒设备保证不会在睡眠模式错过闹钟第二个参数是闹钟的触发时间第三个就是指定谁到时候就会
//被触发
} while (c.moveToNext());//只要下一个数据存在的话
}
c.close();//关闭流文件
}
}
}

@ -0,0 +1,33 @@
/*
* 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.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/*
Author:
Data:2023/4/12
*/
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
intent.setClass(context, AlarmAlertActivity.class);//由当前页面跳转到对应界面
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//该标记表示在新任务栈中启动 Activity当它不在前台的时候保证其可以在后台显示
context.startActivity(intent);//启动对应的活动
}
}

@ -0,0 +1,489 @@
/*
* 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 java.text.DateFormatSymbols;
import java.util.Calendar;
import net.micode.notes.R;
import android.content.Context;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.NumberPicker;
/*
Author:
Data:2023/4/12
*/
public class DateTimePicker extends FrameLayout {
private static final boolean DEFAULT_ENABLE_STATE = true;
private static final int HOURS_IN_HALF_DAY = 12;
private static final int HOURS_IN_ALL_DAY = 24;
private static final int DAYS_IN_ALL_WEEK = 7;
private static final int DATE_SPINNER_MIN_VAL = 0;
private static final int DATE_SPINNER_MAX_VAL = DAYS_IN_ALL_WEEK - 1;
private static final int HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0;
private static final int HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW = 23;
private static final int HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW = 1;
private static final int HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW = 12;
private static final int MINUT_SPINNER_MIN_VAL = 0;
private static final int MINUT_SPINNER_MAX_VAL = 59;
private static final int AMPM_SPINNER_MIN_VAL = 0;
private static final int AMPM_SPINNER_MAX_VAL = 1;
private final NumberPicker mDateSpinner;
private final NumberPicker mHourSpinner;
private final NumberPicker mMinuteSpinner;
private final NumberPicker mAmPmSpinner;
private Calendar mDate;
private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK];
private boolean mIsAm;
private boolean mIs24HourView;
private boolean mIsEnabled = DEFAULT_ENABLE_STATE;
private boolean mInitialising;
private OnDateTimeChangedListener mOnDateTimeChangedListener;
private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {//更改日期
mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal);
updateDateControl();
onDateTimeChanged();
}
};//当用户更改值之后改变便签的修改日期
private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {//各自的参数代表被改变值得NumberPicker对象旧值新值
boolean isDateChanged = false;//用户是否改变值
Calendar cal = Calendar.getInstance();//获取当前的时间
if (!mIs24HourView) {//不是用的24小时制度
if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) {//是下午旧值是11新值是12代表到了下一天
cal.setTimeInMillis(mDate.getTimeInMillis());//将修改时间修改为当前的时间
cal.add(Calendar.DAY_OF_YEAR, 1);//过了一天将日期加1
isDateChanged = true;
} else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {//如果当前是上午,并且
//旧值是12新值是11那么就代表回到了上一天
cal.setTimeInMillis(mDate.getTimeInMillis());//获取当前的时间
cal.add(Calendar.DAY_OF_YEAR, -1);//日期减一
isDateChanged = true;
}
if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY ||
oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {//只要之前是11现在是12或者是之前是12现在是11AM和PM都会发生改变取反
mIsAm = !mIsAm;
updateAmPmControl();//更新限制
}
} else {
if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {//如果当前时间比之前时间早,代表已经过了一天了
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
} else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {//如果当前时间比之前时间晚代表是同一天
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
isDateChanged = true;
}
}
int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY);
mDate.set(Calendar.HOUR_OF_DAY, newHour);
onDateTimeChanged();
if (isDateChanged) {
setCurrentYear(cal.get(Calendar.YEAR));
setCurrentMonth(cal.get(Calendar.MONTH));
setCurrentDay(cal.get(Calendar.DAY_OF_MONTH));
}
}
};
private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {//通过调整分钟来调整时间
int minValue = mMinuteSpinner.getMinValue();//获取最小值
int maxValue = mMinuteSpinner.getMaxValue();//获取最大值
int offset = 0;//判断是否跨越边界
if (oldVal == maxValue && newVal == minValue) {//如果新的是最小的旧的值是最大的那么小时加1
offset += 1;
} else if (oldVal == minValue && newVal == maxValue) {//如果新的是最大的值,旧的是最小值,那么代表我们是往上调整的,那么小时减小
offset -= 1;
}
if (offset != 0) {//如果跨越边界了
mDate.add(Calendar.HOUR_OF_DAY, offset);//日期进行相应的改变
mHourSpinner.setValue(getCurrentHour());//获取当前的时间
updateDateControl();//更新限制
int newHour = getCurrentHourOfDay();//更新小时
if (newHour >= HOURS_IN_HALF_DAY) {//判断是上午还是下午
mIsAm = false;//不是上午
updateAmPmControl();//更新限制
} else {
mIsAm = true;//是上午
updateAmPmControl();
}
}
mDate.set(Calendar.MINUTE, newVal);//设置成新的值
onDateTimeChanged();//更改小时
}
};
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {//更新上午还是下午
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
mIsAm = !mIsAm;//上午变成下午,下午变成上午
if (mIsAm) {
mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY);//如果是下午变成上午那么需要减去12小时
} else {
mDate.add(Calendar.HOUR_OF_DAY, HOURS_IN_HALF_DAY);//如果是上午变成下午那么需要加上12小时
}
updateAmPmControl();
onDateTimeChanged();
}
};
public interface OnDateTimeChangedListener {
void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute);
}
public DateTimePicker(Context context) {
this(context, System.currentTimeMillis());
}
public DateTimePicker(Context context, long date) {
this(context, date, DateFormat.is24HourFormat(context));
}
public DateTimePicker(Context context, long date, boolean is24HourView) {
super(context);
mDate = Calendar.getInstance();
mInitialising = true;
mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY;
inflate(context, R.layout.datetime_picker, this);//将小时、分钟和日期、在上午还是下午填充到这个文件中
mDateSpinner = (NumberPicker) findViewById(R.id.date);
mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL);//选择当前月份的最小的那一天
mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL);//选择当前月份最大的那一天
mDateSpinner.setOnValueChangedListener(mOnDateChangedListener);//设置日期监听器
mHourSpinner = (NumberPicker) findViewById(R.id.hour);//找到小时
mHourSpinner.setOnValueChangedListener(mOnHourChangedListener);//设置小时监听器
mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL);//设置分钟最小值
mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL);//设置分钟最大值
mMinuteSpinner.setOnLongPressUpdateInterval(100);//设置按下更新的间隔是100ms
mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener);//设置分钟监听器
String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings();//获取当前设备上的AM/PM字符串数组第一个元素为AM第二个元素为PM
mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm);
mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL);
mAmPmSpinner.setMaxValue(AMPM_SPINNER_MAX_VAL);
mAmPmSpinner.setDisplayedValues(stringsForAmPm);
mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener);//设置上午下午监听器
// update controls to initial state
updateDateControl();//更新限制
updateHourControl();
updateAmPmControl();
set24HourView(is24HourView);
// set to current time
setCurrentDate(date);
setEnabled(isEnabled());
// set the content descriptions
mInitialising = false;
}
@Override
public void setEnabled(boolean enabled) {//用来设置组件显示出来
if (mIsEnabled == enabled) {//如果相同则不用修改
return;
}
super.setEnabled(enabled);//设置可行
mDateSpinner.setEnabled(enabled);//设置日期监听器可行
mMinuteSpinner.setEnabled(enabled);//设置分钟监听器可行
mHourSpinner.setEnabled(enabled);//设置小时监听器可行
mAmPmSpinner.setEnabled(enabled);//设置上午下午监听器可行
mIsEnabled = enabled;//设置为已经更新为可用
}
@Override
public boolean isEnabled() {
return mIsEnabled;
}//返回是否可用
/**
* Get the current date in millis
*
* @return the current date in millis
*/
public long getCurrentDateInTimeMillis() {
return mDate.getTimeInMillis();
}//获取当前的日期
/**
* Set the current date
*
* @param date The current date in millis
*/
public void setCurrentDate(long date) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(date);
setCurrentDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
}
/**
* Set the current date
*
* @param year The current year
* @param month The current month
* @param dayOfMonth The current dayOfMonth
* @param hourOfDay The current hourOfDay
* @param minute The current minute
*/
public void setCurrentDate(int year, int month,
int dayOfMonth, int hourOfDay, int minute) {
setCurrentYear(year);
setCurrentMonth(month);
setCurrentDay(dayOfMonth);
setCurrentHour(hourOfDay);
setCurrentMinute(minute);
}//设置时间
/**
* Get current year
*
* @return The current year
*/
public int getCurrentYear() {
return mDate.get(Calendar.YEAR);
}//返回当前年
/**
* Set current year
*
* @param year The current year
*/
public void setCurrentYear(int year) {
if (!mInitialising && year == getCurrentYear()) {//如果已经初始化并且年份和当前的相同
return;
}
mDate.set(Calendar.YEAR, year);//更新
updateDateControl();
onDateTimeChanged();
}
/**
* Get current month in the year
*
* @return The current month in the year
*/
public int getCurrentMonth() {
return mDate.get(Calendar.MONTH);
}//获得月份
/**
* Set current month in the year
*
* @param month The month in the year
*/
public void setCurrentMonth(int month) {
if (!mInitialising && month == getCurrentMonth()) {
return;
}
mDate.set(Calendar.MONTH, month);//更新月份
updateDateControl();
onDateTimeChanged();
}
/**
* Get current day of the month
*
* @return The day of the month
*/
public int getCurrentDay() {
return mDate.get(Calendar.DAY_OF_MONTH);
}//获取月份
/**
* Set current day of the month
*
* @param dayOfMonth The day of the month
*/
public void setCurrentDay(int dayOfMonth) {//更新天
if (!mInitialising && dayOfMonth == getCurrentDay()) {
return;
}
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
updateDateControl();
onDateTimeChanged();
}
/**
* Get current hour in 24 hour mode, in the range (0~23)
* @return The current hour in 24 hour mode
*/
public int getCurrentHourOfDay() {
return mDate.get(Calendar.HOUR_OF_DAY);
}//获取当前的小时
private int getCurrentHour() {
if (mIs24HourView){//如果是24小时
return getCurrentHourOfDay();
} else {
int hour = getCurrentHourOfDay();//获取小时
if (hour > HOURS_IN_HALF_DAY) {//如果大于12应该减去12
return hour - HOURS_IN_HALF_DAY;
} else {
return hour == 0 ? HOURS_IN_HALF_DAY : hour;//否则就和当前的相同
}
}
}
/**
* Set current hour in 24 hour mode, in the range (0~23)
*
* @param hourOfDay
*/
public void setCurrentHour(int hourOfDay) {
if (!mInitialising && hourOfDay == getCurrentHourOfDay()) {//如果已经初始化并且和现在的小时一样就不用管
return;
}
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);//设置小时
if (!mIs24HourView) {//如果不是24小时制度
if (hourOfDay >= HOURS_IN_HALF_DAY) {
mIsAm = false;//代表是下午
if (hourOfDay > HOURS_IN_HALF_DAY) {//如果大于12
hourOfDay -= HOURS_IN_HALF_DAY;
}
} else {
mIsAm = true;//时上午
if (hourOfDay == 0) {
hourOfDay = HOURS_IN_HALF_DAY;//代表到达了最后
}
}
updateAmPmControl();
}
mHourSpinner.setValue(hourOfDay);//更新时间
onDateTimeChanged();
}
/**
* Get currentMinute
*
* @return The Current Minute
*/
public int getCurrentMinute() {
return mDate.get(Calendar.MINUTE);
}
/**
* Set current minute
*/
public void setCurrentMinute(int minute) {
if (!mInitialising && minute == getCurrentMinute()) {
return;
}
mMinuteSpinner.setValue(minute);//设置时间
mDate.set(Calendar.MINUTE, minute);//设置分钟
onDateTimeChanged();
}
/**
* @return true if this is in 24 hour view else false.
*/
public boolean is24HourView () {
return mIs24HourView;
}//返回是否是24小时制
/**
* Set whether in 24 hour or AM/PM mode.
*
* @param is24HourView True for 24 hour mode. False for AM/PM mode.
*/
public void set24HourView(boolean is24HourView) {
if (mIs24HourView == is24HourView) {//如果是24小时制就无需更改
return;
}
mIs24HourView = is24HourView;//更改为24小时制度
mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE);//讲对应的界面显示出来
int hour = getCurrentHourOfDay();//获取当前的小时
updateHourControl();
setCurrentHour(hour);//更新时间
updateAmPmControl();
}
private void updateDateControl() {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -DAYS_IN_ALL_WEEK / 2 - 1);//按照一周来显示,以当前这一天为中心进行扩展
mDateSpinner.setDisplayedValues(null);//清空mDateSpinner显示的数据
for (int i = 0; i < DAYS_IN_ALL_WEEK; ++i) {
cal.add(Calendar.DAY_OF_YEAR, 1);//将当前的cal的最后一个数据加1
mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal);//格式化日期
}
mDateSpinner.setDisplayedValues(mDateDisplayValues);//把加入的数据显示出来
mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2);//将选择器的初始位置设置为中心位置
mDateSpinner.invalidate();//使选择器无效,从而更新显示值
}
private void updateAmPmControl() {
if (mIs24HourView) {//如果是24小时制
mAmPmSpinner.setVisibility(View.GONE);//上午下午不显示
} else {
int index = mIsAm ? Calendar.AM : Calendar.PM;//显示是上午还是下午
mAmPmSpinner.setValue(index);//显示对应的内容
mAmPmSpinner.setVisibility(View.VISIBLE);//可见
}
}
private void updateHourControl() {
if (mIs24HourView) {//如果是24小时制
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW);//显示24小时最小值
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW);//显示24小时最大值
} else {
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW);//显示12小时最小值
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW);//显示12小时最大值
}
}
/**
* Set the callback that indicates the 'Set' button has been pressed.
* @param callback the callback, if null will do nothing
*/
public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback) {
mOnDateTimeChangedListener = callback;
}
private void onDateTimeChanged() {//更改便签时间
if (mOnDateTimeChangedListener != null) {
mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(),
getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute());
}
}
}

@ -0,0 +1,90 @@
/*
* 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 java.util.Calendar;
import net.micode.notes.R;
import net.micode.notes.ui.DateTimePicker;
import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
public class DateTimePickerDialog extends AlertDialog implements OnClickListener {
private Calendar mDate = Calendar.getInstance();
private boolean mIs24HourView;
private OnDateTimeSetListener mOnDateTimeSetListener;
private DateTimePicker mDateTimePicker;
public interface OnDateTimeSetListener {
void OnDateTimeSet(AlertDialog dialog, long date);
}
public DateTimePickerDialog(Context context, long date) {
super(context);
mDateTimePicker = new DateTimePicker(context);
setView(mDateTimePicker);//将事件显示出来
mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() {
public void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute) {
mDate.set(Calendar.YEAR, year);
mDate.set(Calendar.MONTH, month);
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
mDate.set(Calendar.MINUTE, minute);
updateTitle(mDate.getTimeInMillis());//更新题目
}//根据对话框参数定位到对应的日期
});
mDate.setTimeInMillis(date);//将其转化为时间戳
mDate.set(Calendar.SECOND, 0);//设置s为0
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis());//将其设置为时间
setButton(context.getString(R.string.datetime_dialog_ok), this);//确认
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null);//显示提示是去校
set24HourView(DateFormat.is24HourFormat(this.getContext()));//根据24小时制或者是12小时进行设置
updateTitle(mDate.getTimeInMillis());//更新题目
}
public void set24HourView(boolean is24HourView) {
mIs24HourView = is24HourView;
}//设置为24小时页面
public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) {
mOnDateTimeSetListener = callBack;
}
private void updateTitle(long date) {
int flag =
DateUtils.FORMAT_SHOW_YEAR |//显示年日时间
DateUtils.FORMAT_SHOW_DATE |
DateUtils.FORMAT_SHOW_TIME;
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR;//是否按照24小时制显示
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag));//设置对应的题目
}
public void onClick(DialogInterface arg0, int arg1) {
if (mOnDateTimeSetListener != null) {
mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis());
}
}
}

@ -0,0 +1,61 @@
/*
* 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.content.Context;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
import net.micode.notes.R;
public class DropdownMenu {
private Button mButton;
private PopupMenu mPopupMenu;
private Menu mMenu;
public DropdownMenu(Context context, Button button, int menuId) {//放下菜单
mButton = button;
mButton.setBackgroundResource(R.drawable.dropdown_icon);//设置背景资源,改变对应的背景图片
mPopupMenu = new PopupMenu(context, mButton);//显示菜单
mMenu = mPopupMenu.getMenu();
mPopupMenu.getMenuInflater().inflate(menuId, mMenu);//填充菜单
mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mPopupMenu.show();
}//显示对应的菜单
});
}
public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) {
if (mPopupMenu != null) {
mPopupMenu.setOnMenuItemClickListener(listener);
}
}
public MenuItem findItem(int id) {
return mMenu.findItem(id);
}
public void setTitle(CharSequence title) {
mButton.setText(title);
}
}

@ -0,0 +1,84 @@
/*
* 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.content.Context;
import android.database.Cursor;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
public class FoldersListAdapter extends CursorAdapter {
//CursorAdapter是Cursor和ListView的接口
//FoldersListAdapter继承了CursorAdapter的类
//主要作用是便签数据库和用户的交互
//这里就是用folder文件夹的形式展现给用户
public static final String [] PROJECTION = {
NoteColumns.ID,
NoteColumns.SNIPPET
};//调用数据库中便签的ID和片段
public static final int ID_COLUMN = 0;
public static final int NAME_COLUMN = 1;
public FoldersListAdapter(Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
}//数据库操作
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new FolderListItem(context);
}//创建一个文件夹,对于各文件夹中子标签的初始化
@Override
public void bindView(View view, Context context, Cursor cursor) {
if (view instanceof FolderListItem) {//FolderListItem是显示子图如果view是该类的实例那么就去cursor中获取文件夹的名称并将其绑定到FolderListItem上
String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
((FolderListItem) view).bind(folderName);
}
}//将各个布局文件绑定起来
public String getFolderName(Context context, int position) {
Cursor cursor = (Cursor) getItem(position);
return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
}//根据数据库中标签的ID得到标签的各项内容
private class FolderListItem extends LinearLayout {
private TextView mName;
public FolderListItem(Context context) {
super(context);//操作数据库
inflate(context, R.layout.folder_list_item, this);
mName = (TextView) findViewById(R.id.tv_folder_name);//根据布局文件的名字等信息将其找出来
}
public void bind(String name) {
mName.setText(name);
}
}
}

@ -0,0 +1,873 @@
/*
* 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.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.SearchManager;
import android.appwidget.AppWidgetManager;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Paint;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.style.BackgroundColorSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.ImageView;
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.data.Notes.TextNote;
import net.micode.notes.model.WorkingNote;
import net.micode.notes.model.WorkingNote.NoteSettingChangedListener;
import net.micode.notes.tool.DataUtils;
import net.micode.notes.tool.ResourceParser;
import net.micode.notes.tool.ResourceParser.TextAppearanceResources;
import net.micode.notes.ui.DateTimePickerDialog.OnDateTimeSetListener;
import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener;
import net.micode.notes.widget.NoteWidgetProvider_2x;
import net.micode.notes.widget.NoteWidgetProvider_4x;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NoteEditActivity extends Activity implements OnClickListener,
NoteSettingChangedListener, OnTextViewChangeListener {
private class HeadViewHolder {
public TextView tvModified;
public ImageView ivAlertIcon;
public TextView tvAlertDate;
public ImageView ibSetBgColor;
}
private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>();//将小米便签的背景颜色映射成一个个值
static {
sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW);
sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED);
sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE);
sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN);
sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE);
}
private static final Map<Integer, Integer> sBgSelectorSelectionMap = new HashMap<Integer, Integer>();//将映射的颜色在反射为小米便签对应颜色的一个值
static {
sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select);
sBgSelectorSelectionMap.put(ResourceParser.RED, R.id.iv_bg_red_select);
sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select);
sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select);
sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select);
}
private static final Map<Integer, Integer> sFontSizeBtnsMap = new HashMap<Integer, Integer>();//将字体大小映射为一个值
static {
sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE);
sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL);
sFontSizeBtnsMap.put(R.id.ll_font_normal, ResourceParser.TEXT_MEDIUM);
sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER);
}
private static final Map<Integer, Integer> sFontSelectorSelectionMap = new HashMap<Integer, Integer>();//将映射的值重新反射为字体大小对应的值
static {
sFontSelectorSelectionMap.put(ResourceParser.TEXT_LARGE, R.id.iv_large_select);
sFontSelectorSelectionMap.put(ResourceParser.TEXT_SMALL, R.id.iv_small_select);
sFontSelectorSelectionMap.put(ResourceParser.TEXT_MEDIUM, R.id.iv_medium_select);
sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select);
}
private static final String TAG = "NoteEditActivity";
private HeadViewHolder mNoteHeaderHolder;
private View mHeadViewPanel;
private View mNoteBgColorSelector;
private View mFontSizeSelector;
private EditText mNoteEditor;
private View mNoteEditorPanel;
private WorkingNote mWorkingNote;
private SharedPreferences mSharedPrefs;
private int mFontSizeId;
private static final String PREFERENCE_FONT_SIZE = "pref_font_size";
private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10;
public static final String TAG_CHECKED = String.valueOf('\u221A');
public static final String TAG_UNCHECKED = String.valueOf('\u25A1');
private LinearLayout mEditTextList;
private String mUserQuery;
private Pattern mPattern;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);//执行父类的初始化操作
this.setContentView(R.layout.note_edit);//将布局文件node_edit加载到activity中并设置为当前的试图
if (savedInstanceState == null && !initActivityState(getIntent())) {//初始化失败
finish();
return;
}
initResources();//进行资源的初始化和加载
}
/**
* Current activity may be killed when the memory is low. Once it is killed, for another time
* user load this activity, we should restore the former state
*/
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {//回复Activities的状态
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null && savedInstanceState.containsKey(Intent.EXTRA_UID)) {//是否包含Intent.EXTRA_UID如果包含则重新恢复
Intent intent = new Intent(Intent.ACTION_VIEW);//创建新的对象并显示出来
intent.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID));//把之前的数据加载到该intent上面来
if (!initActivityState(intent)) {//如果不存在
finish();
return;
}
Log.d(TAG, "Restoring from killed activity");//状态恢复成功
}
}
private boolean initActivityState(Intent intent) {
/**
* If the user specified the {@link Intent#ACTION_VIEW} but not provided with id,
* then jump to the NotesListActivity
*/
mWorkingNote = null;
if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) {
long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0);//获取intent所携带的附加参数
mUserQuery = "";
/**
* Starting from the searched result
*/
if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) {//是否有额外的数据,有的话代表用户想要查看这一个便签
noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));//取出来对应的id以便于之后数据库搜索
mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY);//将mUserQuery设置为用户输入的查询的字符串
}
if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) {//这个便签不能在数据库中找到
Intent jump = new Intent(this, NotesListActivity.class);//跳转到对应NoteListActivities上
startActivity(jump);//跳转
showToast(R.string.error_note_not_exist);//输出这个便签不存在
finish();//关闭页面
return false;
} else {
mWorkingNote = WorkingNote.load(this, noteId);//加载对应的便签
if (mWorkingNote == null) {//加载失败会记录当前的Activity
Log.e(TAG, "load note failed with note id" + noteId);//输出打开失败
finish();
return false;
}
}
getWindow().setSoftInputMode(//设置窗口为软件盘模式,窗口会自动调整布局大小以适应软键盘的显示或隐藏
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN//此标志表示启动该 Activity 时软键盘不会自动弹出
| WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);//Activity 中的窗口大小会根据软键盘的状态自动调整
} else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) {//如果是增添或者编辑
// New note
long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0);//获取FolderId
int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID,//获取传入的组件Id如果没有找到对应的组件Id那么就会返回无效的ID
AppWidgetManager.INVALID_APPWIDGET_ID);
int widgetType = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_TYPE,//获取组件的类型
Notes.TYPE_WIDGET_INVALIDE);
int bgResId = intent.getIntExtra(Notes.INTENT_EXTRA_BACKGROUND_ID,//获取组件的背景Id如果没有就默认的背景颜色
ResourceParser.getDefaultBgId(this));
// Parse call-record note
String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);//获取手机号码
long callDate = intent.getLongExtra(Notes.INTENT_EXTRA_CALL_DATE, 0);//获取通话时间
if (callDate != 0 && phoneNumber != null) {
if (TextUtils.isEmpty(phoneNumber)) {//如果没有该电话号
Log.w(TAG, "The call record number is null");
}
long noteId = 0;
if ((noteId = DataUtils.getNoteIdByPhoneNumberAndCallDate(getContentResolver(),
phoneNumber, callDate)) > 0) {//如果从数据库找到对应的电话号和日期号了那么就进行此操作
mWorkingNote = WorkingNote.load(this, noteId);//加载该便签
if (mWorkingNote == null) {//打开失败
Log.e(TAG, "load call note failed with note id" + noteId);
finish();
return false;
}
} else {//没有对应的日期或者没有对应的电话号码
mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId,
widgetType, bgResId);//新建立一个便签
mWorkingNote.convertToCallNote(phoneNumber, callDate);//转化为电话记录便签
}
} else {//如果有一者为空那么就代表是创建一个普通的便签
mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, widgetType,
bgResId);
}
getWindow().setSoftInputMode(//也是软键盘形式
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
| WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
} else {
Log.e(TAG, "Intent not specified action, should not support");//不支持此类操作。
finish();
return false;
}
mWorkingNote.setOnSettingStatusChangedListener(this);//建立好之后进行监听,对更改或删除便签做相应的改变
return true;
}
@Override
protected void onResume() {//当由后台到前台的时候进行调用
super.onResume();
initNoteScreen();
}
private void initNoteScreen() {
mNoteEditor.setTextAppearance(this, TextAppearanceResources
.getTexAppearanceResource(mFontSizeId));//获取用户当前字体的大小
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {//转化为清单模式
switchToListMode(mWorkingNote.getContent());//获取对应的内容
} else {//如果不是清单模式
mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery));//对用户输入的关键字文本进行高亮显示
mNoteEditor.setSelection(mNoteEditor.getText().length());//获取选取的长度
}
for (Integer id : sBgSelectorSelectionMap.keySet()) {
findViewById(sBgSelectorSelectionMap.get(id)).setVisibility(View.GONE);//找到当前键的值也就是id并隐藏背景选择器选中的背景图
}
mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId());//在头部显示标题
mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId());//在背景显示对应的背景颜色
mNoteHeaderHolder.tvModified.setText(DateUtils.formatDateTime(this,
mWorkingNote.getModifiedDate(), DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_TIME
| DateUtils.FORMAT_SHOW_YEAR));//将修改时间文本视图中的数据写入标题
/**
* TODO: Add the menu for setting alert. Currently disable it because the DateTimePicker
* is not ready
*/
showAlertHeader();//决定是否显示提醒的表头
}
private void showAlertHeader() {
if (mWorkingNote.hasClockAlert()) {//如果有时间提醒
long time = System.currentTimeMillis();//获得当前的时间
if (time > mWorkingNote.getAlertDate()) {//如果超过时间提醒
mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired);//设置提醒日期文本视图为过期显示内容
} else {
mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString(//显示距离提示还有多长时间
mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS));
}
mNoteHeaderHolder.tvAlertDate.setVisibility(View.VISIBLE);//显示提醒日期
mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE);//显示提醒图标
} else {//没有时间提醒就隐藏对应的提醒标志
mNoteHeaderHolder.tvAlertDate.setVisibility(View.GONE);
mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE);
};
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
initActivityState(intent);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
/**
* For new note without note id, we should firstly save it to
* generate a id. If the editing note is not worth saving, there
* is no id which is equivalent to create new note
*/
if (!mWorkingNote.existInDatabase()) {//如果数据库没有就进行保存
saveNote();
}
outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId());//初始化
Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState");//显示对应id信息和保存成功
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {//笔记编辑器的触摸事件
if (mNoteBgColorSelector.getVisibility() == View.VISIBLE
&& !inRangeOfView(mNoteBgColorSelector, ev)) {//如果不在背景颜色选择器的触摸范围之内,并且背景选择器是可视化的
mNoteBgColorSelector.setVisibility(View.GONE);//将背景选择器隐藏起来
return true;
}
if (mFontSizeSelector.getVisibility() == View.VISIBLE//判断字体大小选择器是否显示,并且是否在改变字体大小的控制范围内
&& !inRangeOfView(mFontSizeSelector, ev)) {
mFontSizeSelector.setVisibility(View.GONE);//将其隐藏起来
return true;
}
return super.dispatchTouchEvent(ev);
}
private boolean inRangeOfView(View view, MotionEvent ev) {
int []location = new int[2];//获取位置
view.getLocationOnScreen(location);//获取鼠标所在屏幕的左上角对应位置
int x = location[0];//横坐标
int y = location[1];//纵坐标
if (ev.getX() < x
|| ev.getX() > (x + view.getWidth())
|| ev.getY() < y
|| ev.getY() > (y + view.getHeight())) {
return false;
}//ev.getX获取了触摸事件的横坐标getY则是获取纵坐标该判断语句就是判断触摸事件的横纵坐标在该视图的外部
return true;//在管辖范畴内
}
private void initResources() {
mHeadViewPanel = findViewById(R.id.note_title);//获取对应id的视图
mNoteHeaderHolder = new HeadViewHolder();//实例化头部信息
mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date);//把修改日期视图封装在mNoteHeaderHolder中
mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon);//把提醒图标视图封装在对象中
mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date);//把提醒日期视图封装在对象中
mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color);//把改变背景颜色的视图封装在对象中
mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this);//设置对应的监听器
mNoteEditor = (EditText) findViewById(R.id.note_edit_view);//找到对应的编辑器视图
mNoteEditorPanel = findViewById(R.id.sv_note_edit);//把保存便签的视图放在该对象中
mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector);//将背景颜色选择器捆绑给mNoteBgColorSelector中
for (int id : sBgSelectorBtnsMap.keySet()) {//为每一种背景颜色对应的视图设置监听器
ImageView iv = (ImageView) findViewById(id);
iv.setOnClickListener(this);
}
mFontSizeSelector = findViewById(R.id.font_size_selector);//捆绑字体大小选择器
for (int id : sFontSizeBtnsMap.keySet()) {//为每一种字体大小设置监听器
View view = findViewById(id);
view.setOnClickListener(this);
};
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);//获取默认的共享偏好
mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE);//设置字体大小
/**
* HACKME: Fix bug of store the resource id in shared preference.
* The id may larger than the length of resources, in this case,
* return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE}
*/
if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) {//如果设置的字体大小的id超过了限制那么就重新调回默认的字体大小
mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE;
}
mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list);//线性放置
}
@Override
protected void onPause() {
super.onPause();
if(saveNote()) {
Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length());
}//提示已保存对应文本
clearSettingState();
}
private void updateWidget() {//更新widget
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) {//更新到2x大小
intent.setClass(this, NoteWidgetProvider_2x.class);
} else if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_4X) {//更新到4x大小
intent.setClass(this, NoteWidgetProvider_4x.class);
} else {
Log.e(TAG, "Unspported widget type");
return;
}
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {//把对应id附加上去
mWorkingNote.getWidgetId()
});
sendBroadcast(intent);//让widget进行刷新操作从而实现数据同步
setResult(RESULT_OK, intent);
}
public void onClick(View v) {
int id = v.getId();//获取id号
if (id == R.id.btn_set_bg_color) {//如果设置背景颜色
mNoteBgColorSelector.setVisibility(View.VISIBLE);//将改变颜色的视图显示出来
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.VISIBLE);
} else if (sBgSelectorBtnsMap.containsKey(id)) {//如果是背景选择按钮包含此id
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.GONE);//将选择视图关闭
mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id));//设置对应的背景颜色
mNoteBgColorSelector.setVisibility(View.GONE);//
} else if (sFontSizeBtnsMap.containsKey(id)) {//点击的是某个字体大小的图标
findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE);//将选择字体大小的视图关闭
mFontSizeId = sFontSizeBtnsMap.get(id);//将当前的字体大小设置为所选的大小
mSharedPrefs.edit().putInt(PREFERENCE_FONT_SIZE, mFontSizeId).commit();//共享字体大小偏好设置为对应的字体大小
findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE);//显示对应的字体
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {//判断是否为检查模式
getWorkingText();//获取工作中的文本内容
switchToListMode(mWorkingNote.getContent());//转化为列表模式
} else {
mNoteEditor.setTextAppearance(this,
TextAppearanceResources.getTexAppearanceResource(mFontSizeId));//显示字体大小
}
mFontSizeSelector.setVisibility(View.GONE);//关闭字体大小显示
}
}
@Override
public void onBackPressed() {
if(clearSettingState()) {//关闭对应的窗口
return;
}
saveNote();//保存笔记
super.onBackPressed();
}
private boolean clearSettingState() {
if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) {//判断背景颜色选择器是否可见
mNoteBgColorSelector.setVisibility(View.GONE);//关闭
return true;
} else if (mFontSizeSelector.getVisibility() == View.VISIBLE) {//判断字体大小是否可见
mFontSizeSelector.setVisibility(View.GONE);//关闭
return true;
}
return false;
}
public void onBackgroundColorChanged() {
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.VISIBLE);//找到对应颜色的id并进行视图显示
mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId());//编辑面板进行显示
mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId());//试图面板显示
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (isFinishing()) {//页面完成
return true;
}
clearSettingState();//关闭设置的状态
menu.clear();//清空菜单
if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) {
getMenuInflater().inflate(R.menu.call_note_edit, menu);//进行菜单的填充
} else {
getMenuInflater().inflate(R.menu.note_edit, menu);
}
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_normal_mode);//切换为正常模式
} else {
menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_list_mode);
}
if (mWorkingNote.hasClockAlert()) {//显示是否有闹钟提示
menu.findItem(R.id.menu_alert).setVisible(false);//关闭提示
} else {
menu.findItem(R.id.menu_delete_remind).setVisible(false);//菜单删除提醒关闭
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {//根据选项的id号进行对应的选择
case R.id.menu_new_note:
createNewNote();//创建新的标签
break;
case R.id.menu_delete:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.alert_title_delete));//提醒是否要删除
builder.setIcon(android.R.drawable.ic_dialog_alert);//设置删除的图标
builder.setMessage(getString(R.string.alert_message_delete_note));//提示要不要删除
builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {//确定按钮
public void onClick(DialogInterface dialog, int which) {
deleteCurrentNote();//删除当前的便签
finish();
}
});
builder.setNegativeButton(android.R.string.cancel, null);//不确定
builder.show();//继续展示对应界面
break;
case R.id.menu_font_size://字体大小菜单
mFontSizeSelector.setVisibility(View.VISIBLE);//显示字体选择器
findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE);//将字体大小选择器显示出来
break;
case R.id.menu_list_mode:
mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ?
TextNote.MODE_CHECK_LIST : 0);//设置列表模式
break;
case R.id.menu_share://进行菜单分享
getWorkingText();//获取便签的内容
sendTo(this, mWorkingNote.getContent());
break;
case R.id.menu_send_to_desktop:
sendToDesktop();//发送到桌面上
break;
case R.id.menu_alert:
setReminder();//设置提醒器
break;
case R.id.menu_delete_remind:
mWorkingNote.setAlertDate(0, false);//设置日期提醒器
break;
default:
break;
}
return true;
}
private void setReminder() {//设置提醒器
DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis());//设置新的对话框
d.setOnDateTimeSetListener(new OnDateTimeSetListener() {//设置监听器
public void OnDateTimeSet(AlertDialog dialog, long date) {
mWorkingNote.setAlertDate(date , true);//设置信息
}
});
d.show();
}
/**
* Share note to apps that support {@link Intent#ACTION_SEND} action
* and {@text/plain} type
*/
private void sendTo(Context context, String info) {
Intent intent = new Intent(Intent.ACTION_SEND);//代表发送一个文本信息
intent.putExtra(Intent.EXTRA_TEXT, info);//向intend中加入文本信息
intent.setType("text/plain");//文本类型
context.startActivity(intent);//启动这个intent也就是发送信息
}
private void createNewNote() {
// Firstly, save current editing notes
saveNote();
// For safety, start a new NoteEditActivity
finish();
Intent intent = new Intent(this, NoteEditActivity.class);//新建一个intent
intent.setAction(Intent.ACTION_INSERT_OR_EDIT);//设置为编辑或者插入
intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId());//给id
startActivity(intent);//进行相应的编辑活动
}
private void deleteCurrentNote() {
if (mWorkingNote.existInDatabase()) {//如果对应的便签在数据库中能找到的话
HashSet<Long> ids = new HashSet<Long>();
long id = mWorkingNote.getNoteId();
if (id != Notes.ID_ROOT_FOLDER) {//如果不是无效值
ids.add(id);//加入
} else {
Log.d(TAG, "Wrong note id, should not happen");//不存在这样的便签id
}
if (!isSyncMode()) {//不是在同步模式下
if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) {//批量删除失败
Log.e(TAG, "Delete Note error");
}
} else {
if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) {//无法移动到垃圾箱
Log.e(TAG, "Move notes to trash folder error, should not happens");
}
}
}
mWorkingNote.markDeleted(true);//标记为已经删除
}
private boolean isSyncMode() {
return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0;//获取账号名称,如果不是空则代表是同步模式下
}
public void onClockAlertChanged(long date, boolean set) {
/**
* User could set clock to an unsaved note, so before setting the
* alert clock, we should save the note first
*/
if (!mWorkingNote.existInDatabase()) {//如果不在数据库中
saveNote();//保存
}
if (mWorkingNote.getNoteId() > 0) {//如果id为有效id
Intent intent = new Intent(this, AlarmReceiver.class);//新建intent
intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId()));//设置对应的日期,和对应的信息
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);//设置触发intent
AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE));//设置闹钟提醒
showAlertHeader();//显示提醒的标题
if(!set) {//如果要关闭提醒
alarmManager.cancel(pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent);//设置提醒
}
} else {
/**
* There is the condition that user has input nothing (the note is
* not worthy saving), we have no note id, remind the user that he
* should input something
*/
Log.e(TAG, "Clock alert setting error");
showToast(R.string.error_note_empty_for_clock);
}
}
public void onWidgetChanged() {
updateWidget();
}
public void onEditTextDelete(int index, String text) {
int childCount = mEditTextList.getChildCount();//获取当前便签列表的孩子个数
if (childCount == 1) {//如果只有一个孩子
return;
}
for (int i = index + 1; i < childCount; i++) {
((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text))
.setIndex(i - 1);//将index后的文本往前移动
}
mEditTextList.removeViewAt(index);//把对应下标的列表内容删除
NoteEditText edit = null;
if(index == 0) {//如果下标是0那么就获取第一个标签
edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById(
R.id.et_edit_text);
} else {//否则就是下标减一,因为删除了一个元素
edit = (NoteEditText) mEditTextList.getChildAt(index - 1).findViewById(
R.id.et_edit_text);
}
int length = edit.length();
edit.append(text);//把对应的文本内容加入
edit.requestFocus();//获取焦点
edit.setSelection(length);//设置光标到对应的长度
}
public void onEditTextEnter(int index, String text) {
/**
* Should not happen, check for debug
*/
if(index > mEditTextList.getChildCount()) {//如果输入的下标大于孩子的数量,越界访问
Log.e(TAG, "Index out of mEditTextList boundrary, should not happen");
}
View view = getListItem(text, index);//获取对应下标的列表物品的视图
mEditTextList.addView(view, index);//把对应下标的视图放到编辑文本的列表中
NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);//
edit.requestFocus();//获取编辑文本的焦点
edit.setSelection(0);//设置光标到最开始的位置
for (int i = index + 1; i < mEditTextList.getChildCount(); i++) {//保证NoteEditText的索引值和列表元素的实际位置一致
((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text))
.setIndex(i);
}
}
private void switchToListMode(String text) {
mEditTextList.removeAllViews();//关掉所有的视图
String[] items = text.split("\n");//将对应的文本据回车分开
int index = 0;
for (String item : items) {//遍历里面的元素
if(!TextUtils.isEmpty(item)) {//如果对应文本不是空
mEditTextList.addView(getListItem(item, index));//增加一个视图,并标上下标
index++;//到达下一个
}
}
mEditTextList.addView(getListItem("", index));//用于添加新的列表项目
mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus();//请求焦点
mNoteEditor.setVisibility(View.GONE);//将便签编辑器取消
mEditTextList.setVisibility(View.VISIBLE);//将便文本列表显示出来
}
private Spannable getHighlightQueryResult(String fullText, String userQuery) {//将搜索到的关键字通过高亮显示出来
SpannableString spannable = new SpannableString(fullText == null ? "" : fullText);
if (!TextUtils.isEmpty(userQuery)) {//判断用户查询的内容是否为空
mPattern = Pattern.compile(userQuery);//将对应得文本转化为匹配模式
Matcher m = mPattern.matcher(fullText);//把对应得文本匹配出来
int start = 0;//定义开始
while (m.find(start)) {//到达下一个位置
spannable.setSpan(
new BackgroundColorSpan(this.getResources().getColor(
R.color.user_query_highlight)), m.start(), m.end(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);//设置对应得高亮模式
start = m.end();//更新扫描得开始位置
}
}
return spannable;
}
private View getListItem(String item, int index) {
View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null);//获取布局解析器对象
final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);//找到对应id得控件对象
edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId));//设置文本形式
CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item));//根据id找到对应的多选框
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {//监听复选框的变化
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {//勾选了对应的复选框
edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);//加上对应的删除线
} else {//取消了勾选
edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);//删除对应的删除线
}
}
});
if (item.startsWith(TAG_CHECKED)) {//如果该列表项已经被勾选了
cb.setChecked(true);//设置为选中状态
edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);//
item = item.substring(TAG_CHECKED.length(), item.length()).trim();//修剪掉对应的空格
} else if (item.startsWith(TAG_UNCHECKED)) {
cb.setChecked(false);
edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);//未勾选状态
item = item.substring(TAG_UNCHECKED.length(), item.length()).trim();//去除TAG_UNCHECKED前缀
}
edit.setOnTextViewChangeListener(this);//给当前事件捆绑监听器
edit.setIndex(index);
edit.setText(getHighlightQueryResult(item, mUserQuery));//对用户的查询显示高亮
return view;
}
public void onTextChange(int index, boolean hasText) {
if (index >= mEditTextList.getChildCount()) {//看坐标是否大于子控件数目如果大于,是无效操作
Log.e(TAG, "Wrong index, should not happen");
return;
}
if(hasText) {//决定左侧检查框是否显示,如果是有文本的,获取对应位置的子控件
mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE);//将对应的多选框筛查出来
} else {
mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE);
}
}
public void onCheckListModeChanged(int oldMode, int newMode) {
if (newMode == TextNote.MODE_CHECK_LIST) {//如果是在检查列表模式下
switchToListMode(mNoteEditor.getText().toString());//转化为列表模式
} else {
if (!getWorkingText()) {
mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ",
""));
}
mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery));//
mEditTextList.setVisibility(View.GONE);//
mNoteEditor.setVisibility(View.VISIBLE);//
}
}
private boolean getWorkingText() {//根据文本内容和勾选状态生成字符串,统计用户的输入状态
boolean hasChecked = false;
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {//如果是勾选列表模式
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mEditTextList.getChildCount(); i++) {
View view = mEditTextList.getChildAt(i);//获取对应构件
NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
if (!TextUtils.isEmpty(edit.getText())) {//获取输入框的内容
if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) {//如果当前的遍历的多选框被勾选了
sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n");//将该信息加入到sb中
hasChecked = true;
} else {
sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n");//没有勾选
}
}
}
mWorkingNote.setWorkingText(sb.toString());//将其转化为String类
} else {
mWorkingNote.setWorkingText(mNoteEditor.getText().toString());//设置文本内容
}
return hasChecked;//存在勾选的选项
}
private boolean saveNote() {
getWorkingText();
boolean saved = mWorkingNote.saveNote();
if (saved) {
/**
* There are two modes from List view to edit view, open one note,
* create/edit a node. Opening node requires to the original
* position in the list when back from edit view, while creating a
* new node requires to the top of the list. This code
* {@link #RESULT_OK} is used to identify the create/edit state
*/
setResult(RESULT_OK);
}
return saved;
}
private void sendToDesktop() {
/**
* Before send message to home, we should make sure that current
* editing note is exists in databases. So, for new note, firstly
* save it
*/
if (!mWorkingNote.existInDatabase()) {
saveNote();
}
if (mWorkingNote.getNoteId() > 0) {
Intent sender = new Intent();
Intent shortcutIntent = new Intent(this, NoteEditActivity.class);//表示点击桌面快捷方式需要启动的activity
shortcutIntent.setAction(Intent.ACTION_VIEW);
shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId());
sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
sender.putExtra(Intent.EXTRA_SHORTCUT_NAME,
makeShortcutIconTitle(mWorkingNote.getContent()));//表示快捷方式的名字
sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext(this, R.drawable.icon_app));//快捷方式的图标
sender.putExtra("duplicate", true);
sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT");//拟定发送的广播类型
showToast(R.string.info_note_enter_desktop);
sendBroadcast(sender);//创建对应的快捷方式
} else {//对应的便签不存在
/**
* There is the condition that user has input nothing (the note is
* not worthy saving), we have no note id, remind the user that he
* should input something
*/
Log.e(TAG, "Send to desktop error");
showToast(R.string.error_note_empty_for_send_to_desktop);
}
}
private String makeShortcutIconTitle(String content) {
content = content.replace(TAG_CHECKED, "");//去掉对应的标记
content = content.replace(TAG_UNCHECKED, "");
return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0,
SHORTCUT_ICON_TITLE_MAX_LEN) : content;//将便签前几个字作为标题
}
private void showToast(int resId) {
showToast(resId, Toast.LENGTH_SHORT);
}//显示提示信息
private void showToast(int resId, int duration) {
Toast.makeText(this, resId, duration).show();//在指定时间内显示对应的信息
}
}

@ -1,25 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="net.micode.notes"
android:versionCode="1"
android:versionName="0.1" >
android:versionName="0.1">
<uses-sdk android:minSdkVersion="14" />
@ -35,46 +19,49 @@
<application
android:icon="@drawable/icon_app"
android:label="@string/app_name" >
android:label="@string/app_name">
<activity
android:name=".ui.NotesListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/NoteTheme"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
android:uiOptions="splitActionBarWhenNarrow"
android:windowSoftInputMode="adjustPan" >
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.NoteEditActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:launchMode="singleTop"
android:theme="@style/NoteTheme" >
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter android:scheme="http">
<action android:name="android.intent.action.VIEW"
<action
android:name="android.intent.action.VIEW"
tools:ignore="AppLinkUrlError" />
<category android:name="android.intent.category.DEFAULT"
<category
android:name="android.intent.category.DEFAULT"
tools:ignore="AppLinkUrlError" />
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.INSERT_OR_EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
@ -82,15 +69,17 @@
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<activity android:name=".ui.MyPaintToolsActivity"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
</activity>
<provider
android:name="net.micode.notes.data.NotesProvider"
android:name=".data.NotesProvider"
android:authorities="micode_notes"
android:multiprocess="true" />
<receiver
android:name=".widget.NoteWidgetProvider_2x"
android:label="@string/app_widget2x2" >
android:label="@string/app_widget2x2">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
@ -103,8 +92,7 @@
</receiver>
<receiver
android:name=".widget.NoteWidgetProvider_4x"
android:label="@string/app_widget4x4" >
android:label="@string/app_widget4x4">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
@ -115,39 +103,33 @@
android:name="android.appwidget.provider"
android:resource="@xml/widget_4x_info" />
</receiver>
<receiver android:name=".ui.AlarmInitReceiver" >
<receiver android:name=".ui.AlarmInitReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver
android:name="net.micode.notes.ui.AlarmReceiver"
android:process=":remote" >
</receiver>
android:name=".ui.AlarmReceiver"
android:process=":remote"></receiver>
<activity
android:name=".ui.AlarmAlertActivity"
android:label="@string/app_name"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" >
</activity>
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar"></activity>
<activity
android:name="net.micode.notes.ui.NotesPreferenceActivity"
android:name=".ui.NotesPreferenceActivity"
android:label="@string/preferences_title"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Holo.Light" >
</activity>
android:theme="@android:style/Theme.Holo.Light"></activity>
<service
android:name="net.micode.notes.gtask.remote.GTaskSyncService"
android:exported="true" >
</service>
android:name=".gtask.remote.GTaskSyncService"
android:exported="true"></service>
<meta-data
android:name="android.app.default_searchable"
android:value=".ui.NoteEditActivity" />
</application>
</manifest>
</manifest>

@ -165,6 +165,7 @@ public class Notes {
* <P> Type : INTEGER (long) </P>
*/
public static final String VERSION = "version";
public static final String IMAGE="image";
}
public interface DataColumns {
@ -203,6 +204,7 @@ public class Notes {
* <P> Type: TEXT </P>
*/
public static final String CONTENT = "content";
public static final String IMAGE="image";
/**

@ -25,6 +25,7 @@ import android.util.Log;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.model.Note;
public class NotesDatabaseHelper extends SQLiteOpenHelper {
@ -60,8 +61,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
")";
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +","+
NoteColumns.IMAGE + " BLOB DEFAULT NULL"+
")";
private static final String CREATE_DATA_TABLE_SQL =
"CREATE TABLE " + TABLE.DATA + "(" +
@ -322,6 +324,11 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
oldVersion++;
}
if(oldVersion== 4)
{
upgradeToV5(db);
oldVersion++;
}
if (reCreateTriggers) {
reCreateNoteTableTriggers(db);
reCreateDataTableTriggers(db);
@ -359,4 +366,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
}
public void upgradeToV5(SQLiteDatabase db)
{
db.execSQL("ALTER TABLE "+ TABLE.NOTE + " ADD COLUMN " + NoteColumns.IMAGE + "BLOB DEFAULT NULL");
}
}

@ -33,6 +33,7 @@ import net.micode.notes.R;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.NotesDatabaseHelper.TABLE;
import net.micode.notes.model.Note;
public class NotesProvider extends ContentProvider {
@ -163,6 +164,7 @@ public class NotesProvider extends ContentProvider {
}
insertedId = dataId = db.insert(TABLE.DATA, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}

@ -75,6 +75,12 @@ public class Note {
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
public void setImage(String key,byte[] image)
{
mNoteDiffValues.put(key,image);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED,1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE,System.currentTimeMillis());
}
public void setTextData(String key, String value) {
mNoteData.setTextData(key, value);

@ -61,6 +61,8 @@ public class WorkingNote {
private boolean mIsDeleted;
private NoteSettingChangedListener mNoteSettingStatusListener;
private byte[] image;
public boolean isChange=false;
public static final String[] DATA_PROJECTION = new String[] {
DataColumns.ID,
@ -78,11 +80,11 @@ public class WorkingNote {
NoteColumns.BG_COLOR_ID,
NoteColumns.WIDGET_ID,
NoteColumns.WIDGET_TYPE,
NoteColumns.MODIFIED_DATE
NoteColumns.MODIFIED_DATE,
NoteColumns.IMAGE
};
private static final int DATA_ID_COLUMN = 0;
private static final int DATA_CONTENT_COLUMN = 1;
private static final int DATA_MIME_TYPE_COLUMN = 2;
@ -101,6 +103,8 @@ public class WorkingNote {
private static final int NOTE_MODIFIED_DATE_COLUMN = 5;
private static final int NOTE_IMAGE=6;
// New note construct
private WorkingNote(Context context, long folderId) {
mContext = context;
@ -137,6 +141,7 @@ public class WorkingNote {
mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN);
mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN);
mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN);
image=cursor.getBlob(NOTE_IMAGE);
}
cursor.close();
} else {
@ -150,10 +155,11 @@ public class WorkingNote {
Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
DataColumns.NOTE_ID + "=?", new String[] {
String.valueOf(mNoteId)
}, null);
}, null);//调用Content Providers Api接口来获取ContentResolver对象,读取对应文件的数据,就相当于一个数据库
//这里是根据这个便签的id来查找其中string中存储了当前的这个便签的id
if (cursor != null) {
if (cursor.moveToFirst()) {
if (cursor.moveToFirst()) {//是否存在
do {
String type = cursor.getString(DATA_MIME_TYPE_COLUMN);
if (DataConstants.NOTE.equals(type)) {
@ -165,11 +171,11 @@ public class WorkingNote {
} else {
Log.d(TAG, "Wrong note type with type:" + type);
}
} while (cursor.moveToNext());
} while (cursor.moveToNext());//只要没有找到
}
cursor.close();
} else {
Log.e(TAG, "No data with id:" + mNoteId);
Log.e(TAG, "No data with id:" + mNoteId);//打印日志信息
throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId);
}
}
@ -183,20 +189,20 @@ public class WorkingNote {
return note;
}
public static WorkingNote load(Context context, long id) {
public static WorkingNote load(Context context, long id) {//根据id找到对应的便签
return new WorkingNote(context, id, 0);
}
public synchronized boolean saveNote() {
if (isWorthSaving()) {
if (!existInDatabase()) {
if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) {
if (isChange||isWorthSaving()) {//如果值得保存的话就保存
if (!existInDatabase()) {//是否在database中存在
if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) {//创建新的笔记如果创建新的笔记过程中发生异常那么此语句就执行直接返回false
Log.e(TAG, "Create new note fail with id:" + mNoteId);
return false;
}
}
mNote.syncNote(mContext, mNoteId);
mNote.syncNote(mContext, mNoteId);//将新添加的内容和当前id对应的小米便签进行同步
/**
* Update widget content if there exist any widget of this note
@ -206,19 +212,19 @@ public class WorkingNote {
&& mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged();
}
return true;
return true;//当前widgetId合法并且类型和法才进行改变
} else {
return false;
}
}
public boolean existInDatabase() {
public boolean existInDatabase() {//如果数据库中的id小于等于0就代表该id不合法也就是说这个便签不存在于数据库中
return mNoteId > 0;
}
private boolean isWorthSaving() {
if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
|| (existInDatabase() && !mNote.isLocalModified())) {
private boolean isWorthSaving() {//如果当前文件是要进行删除的文件则没有必要保存,不在数据库中也不需要保存,如果内容为空也不用保存,已经在数据库中存在也不需要保存,如果没有改变内容也不需要保存
if ((mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
|| (existInDatabase() && !mNote.isLocalModified()))) {
return false;
} else {
return true;
@ -229,8 +235,8 @@ public class WorkingNote {
mNoteSettingStatusListener = l;
}
public void setAlertDate(long date, boolean set) {
if (date != mAlertDate) {
public void setAlertDate(long date, boolean set) {//设置更改日期
if (date != mAlertDate) {//如果时间不相同
mAlertDate = date;
mNote.setNoteValue(NoteColumns.ALERTED_DATE, String.valueOf(mAlertDate));
}
@ -239,30 +245,30 @@ public class WorkingNote {
}
}
public void markDeleted(boolean mark) {
mIsDeleted = mark;
public void markDeleted(boolean mark) {//mark为1代表要删除为0代表不删除
mIsDeleted = mark;//将对应属性标记为删除
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged();
}
}//如果当前便签的mwidgetid合法类型合法就改变对应的数据
}
public void setBgColorId(int id) {
if (id != mBgColorId) {
public void setBgColorId(int id) {//设置颜色id
if (id != mBgColorId) {//只有当要改的颜色不同的时候才执行该语句
mBgColorId = id;
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onBackgroundColorChanged();
mNoteSettingStatusListener.onBackgroundColorChanged();//改变颜色
}
mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id));
mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id));//更新当前便签的颜色属性值
}
}
public void setCheckListMode(int mode) {
public void setCheckListMode(int mode) {//设置对应的模式
if (mMode != mode) {
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode);
}
mMode = mode;
mMode = mode;//更改模式
mNote.setTextData(TextNote.MODE, String.valueOf(mMode));
}
}
@ -287,6 +293,11 @@ public class WorkingNote {
mNote.setTextData(DataColumns.CONTENT, mContent);
}
}
public void setImage(byte[]image)
{
mNote.setImage(DataColumns.IMAGE,image);
this.image=image;
}
public void convertToCallNote(String phoneNumber, long callDate) {
mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate));
@ -341,6 +352,7 @@ public class WorkingNote {
public int getWidgetType() {
return mWidgetType;
}
public byte[] getImage(){return image;}
public interface NoteSettingChangedListener {
/**

@ -142,7 +142,7 @@ public class ResourceParser {
}
private final static int [] BG_4X_RESOURCES = new int [] {
R.drawable.widget_4x_yellow,
R.drawable.widget_4x_yellow,//widget用来设置图标或者背景可以用来绘制图形
R.drawable.widget_4x_blue,
R.drawable.widget_4x_white,
R.drawable.widget_4x_green,
@ -151,7 +151,7 @@ public class ResourceParser {
public static int getWidget4xBgResource(int id) {
return BG_4X_RESOURCES[id];
}
}//获取对应的颜色
}
public static class TextAppearanceResources {

@ -38,7 +38,10 @@ import net.micode.notes.data.Notes;
import net.micode.notes.tool.DataUtils;
import java.io.IOException;
/*
author:
2023-4-12
*/
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
private long mNoteId;
@ -48,23 +51,23 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);//创建实例
requestWindowFeature(Window.FEATURE_NO_TITLE);//没有标题
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
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);
if (!isScreenOn()) {//在屏幕是关闭的情况下
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON//保持屏幕常亮,以防止设备进入休眠状态。
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON//在锁定状态下唤醒屏幕。如果该标志被设置,则当 Activity 启动时,系统将唤醒设备并点亮屏幕。
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON//允许在屏幕常亮时锁定设备。
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);//允许布局扩展到屏幕装饰区域(例如状态栏)之下。
}
Intent intent = getIntent();
Intent intent = getIntent();//获取页面
try {
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));//找到是否有对应的NoteId
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)
@ -75,9 +78,9 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
mPlayer = new MediaPlayer();
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
showActionDialog();
playAlarmSound();
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {//如果存在对应的便签
showActionDialog();//发出对话框
playAlarmSound();//发出声音
} else {
finish();
}
@ -89,11 +92,12 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
private void playAlarmSound() {
//获取系统中当前默认的闹钟铃声所对应的 Uri并将其赋值给 url 变量
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
//获取当前系统中哪些音频流会受到静音模式的影响
int silentModeStreams = Settings.System.getInt(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
//如果STREAM_ALARM受到影响那么就将音频流形式设置为silentModeStreams
if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) {
mPlayer.setAudioStreamType(silentModeStreams);
} else {
@ -101,7 +105,7 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
try {
mPlayer.setDataSource(this, url);
mPlayer.prepare();
mPlayer.prepare();//于为音频播放做一些准备工作。具体来说,该方法会解析音频数据、分离音频轨道、获取音频格式信息等操作
mPlayer.setLooping(true);
mPlayer.start();
} catch (IllegalArgumentException e) {
@ -121,22 +125,22 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
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);
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.setNegativeButton(R.string.notealert_enter, this);//关闭对话框
}
dialog.show().setOnDismissListener(this);
dialog.show().setOnDismissListener(this);//执行相关的动作
}
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);
Intent intent = new Intent(this, NoteEditActivity.class);//新创建一个页面
intent.setAction(Intent.ACTION_VIEW);//显示页面
intent.putExtra(Intent.EXTRA_UID, mNoteId);//放入对应的数据库中
startActivity(intent);//运行该页面
break;
default:
break;
@ -144,14 +148,14 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
public void onDismiss(DialogInterface dialog) {
stopAlarmSound();
finish();
stopAlarmSound();//关闭闹钟铃声
finish();//该页面结束
}
private void stopAlarmSound() {
if (mPlayer != null) {
mPlayer.stop();
mPlayer.release();
if (mPlayer != null) {//如果该播放器存在
mPlayer.stop();//停下
mPlayer.release();//释放资源
mPlayer = null;
}
}

@ -26,7 +26,10 @@ import android.database.Cursor;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
/*
Author:
Data:2023-4-12
*/
public class AlarmInitReceiver extends BroadcastReceiver {
@ -40,26 +43,28 @@ public class AlarmInitReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
long currentDate = System.currentTimeMillis();
long currentDate = System.currentTimeMillis();//找到目前的时间段
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,
new String[] { String.valueOf(currentDate) },
null);
null);//筛选出来那些提醒时间大于当前时间并且类型是便签类型的
if (c != null) {
if (c.moveToFirst()) {
if (c.moveToFirst()) {//如果下一个数据存在的话
do {
long alertDate = c.getLong(COLUMN_ALERTED_DATE);
Intent sender = new Intent(context, AlarmReceiver.class);
long alertDate = c.getLong(COLUMN_ALERTED_DATE);//获取当前数据的日期
Intent sender = new Intent(context, AlarmReceiver.class);//获取一个新的页面
sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID)));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0);
AlarmManager alermManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent);
} while (c.moveToNext());
alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent);//采用系统实时时钟RTC闹钟
//当闹钟到达alertDate时唤醒设备保证不会在睡眠模式错过闹钟第二个参数是闹钟的触发时间第三个就是指定谁到时候就会
//被触发
} while (c.moveToNext());//只要下一个数据存在的话
}
c.close();
c.close();//关闭流文件
}
}
}

@ -19,12 +19,15 @@ package net.micode.notes.ui;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/*
Author:
Data:2023/4/12
*/
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
intent.setClass(context, AlarmAlertActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
intent.setClass(context, AlarmAlertActivity.class);//由当前页面跳转到对应界面
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//该标记表示在新任务栈中启动 Activity当它不在前台的时候保证其可以在后台显示
context.startActivity(intent);//启动对应的活动
}
}

@ -27,7 +27,10 @@ import android.text.format.DateFormat;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.NumberPicker;
/*
Author:
Data:2023/4/12
*/
public class DateTimePicker extends FrameLayout {
private static final boolean DEFAULT_ENABLE_STATE = true;
@ -66,39 +69,40 @@ public class DateTimePicker extends FrameLayout {
private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {//更改日期
mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal);
updateDateControl();
onDateTimeChanged();
}
};
};//当用户更改值之后改变便签的修改日期
private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
boolean isDateChanged = false;
Calendar cal = Calendar.getInstance();
if (!mIs24HourView) {
if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {//各自的参数代表被改变值得NumberPicker对象旧值新值
boolean isDateChanged = false;//用户是否改变值
Calendar cal = Calendar.getInstance();//获取当前的时间
if (!mIs24HourView) {//不是用的24小时制度
if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) {//是下午旧值是11新值是12代表到了下一天
cal.setTimeInMillis(mDate.getTimeInMillis());//将修改时间修改为当前的时间
cal.add(Calendar.DAY_OF_YEAR, 1);//过了一天将日期加1
isDateChanged = true;
} else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
} else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {//如果当前是上午,并且
//旧值是12新值是11那么就代表回到了上一天
cal.setTimeInMillis(mDate.getTimeInMillis());//获取当前的时间
cal.add(Calendar.DAY_OF_YEAR, -1);//日期减一
isDateChanged = true;
}
if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY ||
oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {//只要之前是11现在是12或者是之前是12现在是11AM和PM都会发生改变取反
mIsAm = !mIsAm;
updateAmPmControl();
updateAmPmControl();//更新限制
}
} else {
if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {
if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {//如果当前时间比之前时间早,代表已经过了一天了
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
} else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {
} else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {//如果当前时间比之前时间晚代表是同一天
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
isDateChanged = true;
@ -117,41 +121,41 @@ public class DateTimePicker extends FrameLayout {
private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
int minValue = mMinuteSpinner.getMinValue();
int maxValue = mMinuteSpinner.getMaxValue();
int offset = 0;
if (oldVal == maxValue && newVal == minValue) {
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {//通过调整分钟来调整时间
int minValue = mMinuteSpinner.getMinValue();//获取最小值
int maxValue = mMinuteSpinner.getMaxValue();//获取最大值
int offset = 0;//判断是否跨越边界
if (oldVal == maxValue && newVal == minValue) {//如果新的是最小的旧的值是最大的那么小时加1
offset += 1;
} else if (oldVal == minValue && newVal == maxValue) {
} else if (oldVal == minValue && newVal == maxValue) {//如果新的是最大的值,旧的是最小值,那么代表我们是往上调整的,那么小时减小
offset -= 1;
}
if (offset != 0) {
mDate.add(Calendar.HOUR_OF_DAY, offset);
mHourSpinner.setValue(getCurrentHour());
updateDateControl();
int newHour = getCurrentHourOfDay();
if (newHour >= HOURS_IN_HALF_DAY) {
mIsAm = false;
updateAmPmControl();
if (offset != 0) {//如果跨越边界了
mDate.add(Calendar.HOUR_OF_DAY, offset);//日期进行相应的改变
mHourSpinner.setValue(getCurrentHour());//获取当前的时间
updateDateControl();//更新限制
int newHour = getCurrentHourOfDay();//更新小时
if (newHour >= HOURS_IN_HALF_DAY) {//判断是上午还是下午
mIsAm = false;//不是上午
updateAmPmControl();//更新限制
} else {
mIsAm = true;
mIsAm = true;//是上午
updateAmPmControl();
}
}
mDate.set(Calendar.MINUTE, newVal);
onDateTimeChanged();
mDate.set(Calendar.MINUTE, newVal);//设置成新的值
onDateTimeChanged();//更改小时
}
};
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {//更新上午还是下午
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
mIsAm = !mIsAm;
mIsAm = !mIsAm;//上午变成下午,下午变成上午
if (mIsAm) {
mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY);
mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY);//如果是下午变成上午那么需要减去12小时
} else {
mDate.add(Calendar.HOUR_OF_DAY, HOURS_IN_HALF_DAY);
mDate.add(Calendar.HOUR_OF_DAY, HOURS_IN_HALF_DAY);//如果是上午变成下午那么需要加上12小时
}
updateAmPmControl();
onDateTimeChanged();
@ -176,30 +180,30 @@ public class DateTimePicker extends FrameLayout {
mDate = Calendar.getInstance();
mInitialising = true;
mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY;
inflate(context, R.layout.datetime_picker, this);
inflate(context, R.layout.datetime_picker, this);//将小时、分钟和日期、在上午还是下午填充到这个文件中
mDateSpinner = (NumberPicker) findViewById(R.id.date);
mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL);
mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL);
mDateSpinner.setOnValueChangedListener(mOnDateChangedListener);
mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL);//选择当前月份的最小的那一天
mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL);//选择当前月份最大的那一天
mDateSpinner.setOnValueChangedListener(mOnDateChangedListener);//设置日期监听器
mHourSpinner = (NumberPicker) findViewById(R.id.hour);
mHourSpinner.setOnValueChangedListener(mOnHourChangedListener);
mHourSpinner = (NumberPicker) findViewById(R.id.hour);//找到小时
mHourSpinner.setOnValueChangedListener(mOnHourChangedListener);//设置小时监听器
mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL);
mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL);
mMinuteSpinner.setOnLongPressUpdateInterval(100);
mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener);
mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL);//设置分钟最小值
mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL);//设置分钟最大值
mMinuteSpinner.setOnLongPressUpdateInterval(100);//设置按下更新的间隔是100ms
mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener);//设置分钟监听器
String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings();
String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings();//获取当前设备上的AM/PM字符串数组第一个元素为AM第二个元素为PM
mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm);
mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL);
mAmPmSpinner.setMaxValue(AMPM_SPINNER_MAX_VAL);
mAmPmSpinner.setDisplayedValues(stringsForAmPm);
mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener);
mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener);//设置上午下午监听器
// update controls to initial state
updateDateControl();
updateDateControl();//更新限制
updateHourControl();
updateAmPmControl();
@ -215,22 +219,22 @@ public class DateTimePicker extends FrameLayout {
}
@Override
public void setEnabled(boolean enabled) {
if (mIsEnabled == enabled) {
public void setEnabled(boolean enabled) {//用来设置组件显示出来
if (mIsEnabled == enabled) {//如果相同则不用修改
return;
}
super.setEnabled(enabled);
mDateSpinner.setEnabled(enabled);
mMinuteSpinner.setEnabled(enabled);
mHourSpinner.setEnabled(enabled);
mAmPmSpinner.setEnabled(enabled);
mIsEnabled = enabled;
super.setEnabled(enabled);//设置可行
mDateSpinner.setEnabled(enabled);//设置日期监听器可行
mMinuteSpinner.setEnabled(enabled);//设置分钟监听器可行
mHourSpinner.setEnabled(enabled);//设置小时监听器可行
mAmPmSpinner.setEnabled(enabled);//设置上午下午监听器可行
mIsEnabled = enabled;//设置为已经更新为可用
}
@Override
public boolean isEnabled() {
return mIsEnabled;
}
}//返回是否可用
/**
* Get the current date in millis
@ -239,7 +243,7 @@ public class DateTimePicker extends FrameLayout {
*/
public long getCurrentDateInTimeMillis() {
return mDate.getTimeInMillis();
}
}//获取当前的日期
/**
* Set the current date
@ -269,7 +273,7 @@ public class DateTimePicker extends FrameLayout {
setCurrentDay(dayOfMonth);
setCurrentHour(hourOfDay);
setCurrentMinute(minute);
}
}//设置时间
/**
* Get current year
@ -278,7 +282,7 @@ public class DateTimePicker extends FrameLayout {
*/
public int getCurrentYear() {
return mDate.get(Calendar.YEAR);
}
}//返回当前年
/**
* Set current year
@ -286,10 +290,10 @@ public class DateTimePicker extends FrameLayout {
* @param year The current year
*/
public void setCurrentYear(int year) {
if (!mInitialising && year == getCurrentYear()) {
if (!mInitialising && year == getCurrentYear()) {//如果已经初始化并且年份和当前的相同
return;
}
mDate.set(Calendar.YEAR, year);
mDate.set(Calendar.YEAR, year);//更新
updateDateControl();
onDateTimeChanged();
}
@ -301,7 +305,7 @@ public class DateTimePicker extends FrameLayout {
*/
public int getCurrentMonth() {
return mDate.get(Calendar.MONTH);
}
}//获得月份
/**
* Set current month in the year
@ -312,7 +316,7 @@ public class DateTimePicker extends FrameLayout {
if (!mInitialising && month == getCurrentMonth()) {
return;
}
mDate.set(Calendar.MONTH, month);
mDate.set(Calendar.MONTH, month);//更新月份
updateDateControl();
onDateTimeChanged();
}
@ -324,14 +328,14 @@ public class DateTimePicker extends FrameLayout {
*/
public int getCurrentDay() {
return mDate.get(Calendar.DAY_OF_MONTH);
}
}//获取月份
/**
* Set current day of the month
*
* @param dayOfMonth The day of the month
*/
public void setCurrentDay(int dayOfMonth) {
public void setCurrentDay(int dayOfMonth) {//更新天
if (!mInitialising && dayOfMonth == getCurrentDay()) {
return;
}
@ -346,17 +350,17 @@ public class DateTimePicker extends FrameLayout {
*/
public int getCurrentHourOfDay() {
return mDate.get(Calendar.HOUR_OF_DAY);
}
}//获取当前的小时
private int getCurrentHour() {
if (mIs24HourView){
if (mIs24HourView){//如果是24小时
return getCurrentHourOfDay();
} else {
int hour = getCurrentHourOfDay();
if (hour > HOURS_IN_HALF_DAY) {
int hour = getCurrentHourOfDay();//获取小时
if (hour > HOURS_IN_HALF_DAY) {//如果大于12应该减去12
return hour - HOURS_IN_HALF_DAY;
} else {
return hour == 0 ? HOURS_IN_HALF_DAY : hour;
return hour == 0 ? HOURS_IN_HALF_DAY : hour;//否则就和当前的相同
}
}
}
@ -367,25 +371,25 @@ public class DateTimePicker extends FrameLayout {
* @param hourOfDay
*/
public void setCurrentHour(int hourOfDay) {
if (!mInitialising && hourOfDay == getCurrentHourOfDay()) {
if (!mInitialising && hourOfDay == getCurrentHourOfDay()) {//如果已经初始化并且和现在的小时一样就不用管
return;
}
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
if (!mIs24HourView) {
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);//设置小时
if (!mIs24HourView) {//如果不是24小时制度
if (hourOfDay >= HOURS_IN_HALF_DAY) {
mIsAm = false;
if (hourOfDay > HOURS_IN_HALF_DAY) {
mIsAm = false;//代表是下午
if (hourOfDay > HOURS_IN_HALF_DAY) {//如果大于12
hourOfDay -= HOURS_IN_HALF_DAY;
}
} else {
mIsAm = true;
mIsAm = true;//时上午
if (hourOfDay == 0) {
hourOfDay = HOURS_IN_HALF_DAY;
hourOfDay = HOURS_IN_HALF_DAY;//代表到达了最后
}
}
updateAmPmControl();
}
mHourSpinner.setValue(hourOfDay);
mHourSpinner.setValue(hourOfDay);//更新时间
onDateTimeChanged();
}
@ -405,8 +409,8 @@ public class DateTimePicker extends FrameLayout {
if (!mInitialising && minute == getCurrentMinute()) {
return;
}
mMinuteSpinner.setValue(minute);
mDate.set(Calendar.MINUTE, minute);
mMinuteSpinner.setValue(minute);//设置时间
mDate.set(Calendar.MINUTE, minute);//设置分钟
onDateTimeChanged();
}
@ -415,7 +419,7 @@ public class DateTimePicker extends FrameLayout {
*/
public boolean is24HourView () {
return mIs24HourView;
}
}//返回是否是24小时制
/**
* Set whether in 24 hour or AM/PM mode.
@ -423,48 +427,48 @@ public class DateTimePicker extends FrameLayout {
* @param is24HourView True for 24 hour mode. False for AM/PM mode.
*/
public void set24HourView(boolean is24HourView) {
if (mIs24HourView == is24HourView) {
if (mIs24HourView == is24HourView) {//如果是24小时制就无需更改
return;
}
mIs24HourView = is24HourView;
mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE);
int hour = getCurrentHourOfDay();
mIs24HourView = is24HourView;//更改为24小时制度
mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE);//讲对应的界面显示出来
int hour = getCurrentHourOfDay();//获取当前的小时
updateHourControl();
setCurrentHour(hour);
setCurrentHour(hour);//更新时间
updateAmPmControl();
}
private void updateDateControl() {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -DAYS_IN_ALL_WEEK / 2 - 1);
mDateSpinner.setDisplayedValues(null);
cal.add(Calendar.DAY_OF_YEAR, -DAYS_IN_ALL_WEEK / 2 - 1);//按照一周来显示,以当前这一天为中心进行扩展
mDateSpinner.setDisplayedValues(null);//清空mDateSpinner显示的数据
for (int i = 0; i < DAYS_IN_ALL_WEEK; ++i) {
cal.add(Calendar.DAY_OF_YEAR, 1);
mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal);
cal.add(Calendar.DAY_OF_YEAR, 1);//将当前的cal的最后一个数据加1
mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal);//格式化日期
}
mDateSpinner.setDisplayedValues(mDateDisplayValues);
mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2);
mDateSpinner.invalidate();
mDateSpinner.setDisplayedValues(mDateDisplayValues);//把加入的数据显示出来
mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2);//将选择器的初始位置设置为中心位置
mDateSpinner.invalidate();//使选择器无效,从而更新显示值
}
private void updateAmPmControl() {
if (mIs24HourView) {
mAmPmSpinner.setVisibility(View.GONE);
if (mIs24HourView) {//如果是24小时制
mAmPmSpinner.setVisibility(View.GONE);//上午下午不显示
} else {
int index = mIsAm ? Calendar.AM : Calendar.PM;
mAmPmSpinner.setValue(index);
mAmPmSpinner.setVisibility(View.VISIBLE);
int index = mIsAm ? Calendar.AM : Calendar.PM;//显示是上午还是下午
mAmPmSpinner.setValue(index);//显示对应的内容
mAmPmSpinner.setVisibility(View.VISIBLE);//可见
}
}
private void updateHourControl() {
if (mIs24HourView) {
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW);
if (mIs24HourView) {//如果是24小时制
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW);//显示24小时最小值
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW);//显示24小时最大值
} else {
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW);
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW);//显示12小时最小值
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW);//显示12小时最大值
}
}
@ -476,7 +480,7 @@ public class DateTimePicker extends FrameLayout {
mOnDateTimeChangedListener = callback;
}
private void onDateTimeChanged() {
private void onDateTimeChanged() {//更改便签时间
if (mOnDateTimeChangedListener != null) {
mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(),
getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute());

@ -43,7 +43,7 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
public DateTimePickerDialog(Context context, long date) {
super(context);
mDateTimePicker = new DateTimePicker(context);
setView(mDateTimePicker);
setView(mDateTimePicker);//将事件显示出来
mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() {
public void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute) {
@ -52,21 +52,21 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
mDate.set(Calendar.MINUTE, minute);
updateTitle(mDate.getTimeInMillis());
}
updateTitle(mDate.getTimeInMillis());//更新题目
}//根据对话框参数定位到对应的日期
});
mDate.setTimeInMillis(date);
mDate.set(Calendar.SECOND, 0);
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis());
setButton(context.getString(R.string.datetime_dialog_ok), this);
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null);
set24HourView(DateFormat.is24HourFormat(this.getContext()));
updateTitle(mDate.getTimeInMillis());
mDate.setTimeInMillis(date);//将其转化为时间戳
mDate.set(Calendar.SECOND, 0);//设置s为0
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis());//将其设置为时间
setButton(context.getString(R.string.datetime_dialog_ok), this);//确认
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null);//显示提示是去校
set24HourView(DateFormat.is24HourFormat(this.getContext()));//根据24小时制或者是12小时进行设置
updateTitle(mDate.getTimeInMillis());//更新题目
}
public void set24HourView(boolean is24HourView) {
mIs24HourView = is24HourView;
}
}//设置为24小时页面
public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) {
mOnDateTimeSetListener = callBack;
@ -74,11 +74,11 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
private void updateTitle(long date) {
int flag =
DateUtils.FORMAT_SHOW_YEAR |
DateUtils.FORMAT_SHOW_YEAR |//显示年日时间
DateUtils.FORMAT_SHOW_DATE |
DateUtils.FORMAT_SHOW_TIME;
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR;
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag));
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR;//是否按照24小时制显示
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag));//设置对应的题目
}
public void onClick(DialogInterface arg0, int arg1) {

@ -32,16 +32,16 @@ public class DropdownMenu {
private PopupMenu mPopupMenu;
private Menu mMenu;
public DropdownMenu(Context context, Button button, int menuId) {
public DropdownMenu(Context context, Button button, int menuId) {//放下菜单
mButton = button;
mButton.setBackgroundResource(R.drawable.dropdown_icon);
mPopupMenu = new PopupMenu(context, mButton);
mButton.setBackgroundResource(R.drawable.dropdown_icon);//设置背景资源,改变对应的背景图片
mPopupMenu = new PopupMenu(context, mButton);//显示菜单
mMenu = mPopupMenu.getMenu();
mPopupMenu.getMenuInflater().inflate(menuId, mMenu);
mPopupMenu.getMenuInflater().inflate(menuId, mMenu);//填充菜单
mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mPopupMenu.show();
}
}//显示对应的菜单
});
}

@ -30,10 +30,14 @@ import net.micode.notes.data.Notes.NoteColumns;
public class FoldersListAdapter extends CursorAdapter {
//CursorAdapter是Cursor和ListView的接口
//FoldersListAdapter继承了CursorAdapter的类
//主要作用是便签数据库和用户的交互
//这里就是用folder文件夹的形式展现给用户
public static final String [] PROJECTION = {
NoteColumns.ID,
NoteColumns.SNIPPET
};
};//调用数据库中便签的ID和片段
public static final int ID_COLUMN = 0;
public static final int NAME_COLUMN = 1;
@ -41,35 +45,35 @@ public class FoldersListAdapter extends CursorAdapter {
public FoldersListAdapter(Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
}
}//数据库操作
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new FolderListItem(context);
}
}//创建一个文件夹,对于各文件夹中子标签的初始化
@Override
public void bindView(View view, Context context, Cursor cursor) {
if (view instanceof FolderListItem) {
if (view instanceof FolderListItem) {//FolderListItem是显示子图如果view是该类的实例那么就去cursor中获取文件夹的名称并将其绑定到FolderListItem上
String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
((FolderListItem) view).bind(folderName);
}
}
}//将各个布局文件绑定起来
public String getFolderName(Context context, int position) {
Cursor cursor = (Cursor) getItem(position);
return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
}
}//根据数据库中标签的ID得到标签的各项内容
private class FolderListItem extends LinearLayout {
private TextView mName;
public FolderListItem(Context context) {
super(context);
super(context);//操作数据库
inflate(context, R.layout.folder_list_item, this);
mName = (TextView) findViewById(R.id.tv_folder_name);
mName = (TextView) findViewById(R.id.tv_folder_name);//根据布局文件的名字等信息将其找出来
}
public void bind(String name) {

@ -31,6 +31,7 @@ import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
@ -78,7 +79,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener {
public class NotesListActivity extends AppCompatActivity implements OnClickListener, OnItemLongClickListener {
private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0;
private static final int FOLDER_LIST_QUERY_TOKEN = 1;

@ -22,7 +22,7 @@
android:minHeight="50dip"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"

@ -58,7 +58,7 @@
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="@drawable/bg_btn_set_color" />
</LinearLayout>
@ -76,12 +76,12 @@
<ScrollView
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_height="616dp"
android:layout_gravity="left|top"
android:layout_weight="1"
android:scrollbars="none"
android:fadingEdgeLength="0dip"
android:overScrollMode="never"
android:layout_gravity="left|top"
android:fadingEdgeLength="0dip">
android:scrollbars="none">
<LinearLayout
android:layout_width="fill_parent"
@ -91,20 +91,20 @@
android:id="@+id/note_edit_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="left|top"
android:background="@null"
android:autoLink="all"
android:background="@null"
android:gravity="left|top"
android:lineSpacingMultiplier="1.2"
android:linksClickable="false"
android:minLines="12"
android:textAppearance="@style/TextAppearancePrimaryItem"
android:lineSpacingMultiplier="1.2" />
android:textAppearance="@style/TextAppearancePrimaryItem" />
<LinearLayout
android:id="@+id/note_edit_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="-10dip"
android:orientation="vertical"
android:visibility="gone" />
</LinearLayout>
</ScrollView>

@ -15,7 +15,8 @@
limitations under the License.
-->
<menu
<menu xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
@ -45,4 +46,13 @@
<item
android:id="@+id/menu_delete_remind"
android:title="@string/menu_remove_remind" />
<item android:title="Item" />
<item
android:id="@+id/menu_Graffiti"
android:title="@string/Graffiti" />
<item
android:id="@+id/app_bar_search"
android:title="Search"
app:actionViewClass="android.widget.SearchView" />
</menu>

@ -45,7 +45,9 @@
<item
android:id="@+id/menu_alert"
android:title="@string/menu_alert" />
<item
android:id="@+id/menu_Graffiti"
android:title="@string/Graffiti" />
<item
android:id="@+id/menu_delete_remind"
android:title="@string/menu_remove_remind" />

@ -15,8 +15,7 @@
limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">Notes</string>
<string name="app_widget2x2">Notes 2x2</string>
<string name="app_widget4x4">Notes 4x4</string>
@ -126,10 +125,11 @@
<string name="search">Notes</string>
<string name="datetime_dialog_ok">set</string>
<string name="datetime_dialog_cancel">cancel</string>
<string name="Graffiti">Graffiti</string>
<plurals name="search_results_title">
<item quantity="one"><xliff:g id="number" example="1">%1$s</xliff:g> result for \"<xliff:g id="search" example="???">%2$s</xliff:g>\"</item>
<item quantity="one"><xliff:g example="1" id="number">%1$s</xliff:g> result for \"<xliff:g example="???" id="search">%2$s</xliff:g>\"</item>
<!-- Case of 0 or 2 or more results. -->
<item quantity="other"><xliff:g id="number" example="15">%1$s</xliff:g> results for \"<xliff:g id="search" example="???">%2$s</xliff:g>\"</item>
<item quantity="other"><xliff:g example="15" id="number">%1$s</xliff:g> results for \"<xliff:g example="???" id="search">%2$s</xliff:g>\"</item>
</plurals>
</resources>

Loading…
Cancel
Save