diff --git a/create.txt b/create.txt new file mode 100644 index 0000000..e69de29 diff --git a/doc/小米便签开源代码泛读报告-吴一凡-202112509022.docx b/doc/小米便签开源代码泛读报告-吴一凡-202112509022.docx new file mode 100644 index 0000000..cc22d6c Binary files /dev/null and b/doc/小米便签开源代码泛读报告-吴一凡-202112509022.docx differ diff --git a/doc/小米便签开源代码质量分析报告.docx b/doc/小米便签开源代码质量分析报告.docx new file mode 100644 index 0000000..a3dfcf1 Binary files /dev/null and b/doc/小米便签开源代码质量分析报告.docx differ diff --git a/file.txt b/file.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/data/Contact.java b/src/data/Contact.java new file mode 100644 index 0000000..0a4cbe1 --- /dev/null +++ b/src/data/Contact.java @@ -0,0 +1,73 @@ +/* + * 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.data; + +import android.content.Context; +import android.database.Cursor; +import android.provider.ContactsContract.CommonDataKinds.Phone; +import android.provider.ContactsContract.Data; +import android.telephony.PhoneNumberUtils; +import android.util.Log; + +import java.util.HashMap; + +public class Contact { + private static HashMap sContactCache; //用散列表缓存联系人 + private static final String TAG = "Contact"; //标识设为”Contact“ + + private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUHashMapMBER + + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" + + " AND " + Data.RAW_CONTACT_ID + " IN " + + "(SELECT raw_contact_id " + + " FROM phone_lookup" + + " WHERE min_match = '+')"; //电话号码数据中查找与给定号码相匹配的联系人信息 + + public static String getContact(Context context, String phoneNumber) { + if(sContactCache == null) { + sContactCache = new HashMap(); + } //若缓存区为空,创建新的散列表 + + if(sContactCache.containsKey(phoneNumber)) { + return sContactCache.get(phoneNumber); + } //查找并返回一个电话号码在联系人缓存中对应的值 + + String selection = CALLER_ID_SELECTION.replace("+", + PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); //将传入的电话号码转换为一个可用于最小匹配的调用者ID格式 + Cursor cursor = context.getContentResolver().query( + Data.CONTENT_URI, + new String [] { Phone.DISPLAY_NAME }, + selection, + new String[] { phoneNumber }, + null);//从联系人数据库中查询与phoneNumber匹配的联系人的显示名称。查询结果将被存储在返回的Cursor对象中,可以遍历这个Cursor来获取每个匹配联系人的显示名称。 + + if (cursor != null && cursor.moveToFirst()) { + try { + String name = cursor.getString(0); + sContactCache.put(phoneNumber, name); + return name; + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, " Cursor get string error " + e.toString()); + return null; + } finally { + cursor.close(); + } + } else { + Log.d(TAG, "No contact matched with number:" + phoneNumber); + return null;//从Android设备的联系人数据库中检索与特定电话号码匹配的联系人名称 + } + } +} diff --git a/src/model/AlarmAlertActivity.java b/src/model/AlarmAlertActivity.java new file mode 100644 index 0000000..0da1caf --- /dev/null +++ b/src/model/AlarmAlertActivity.java @@ -0,0 +1,219 @@ +/* + * 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; +/** + * @ProjectName: Alarm + * @Package: net.micode.notes.ui + * @ClassName: AlarmAlertActivity + * @Description: + * @Author: wyf + * @CreateDate: 2023/12/24 18:00 + */ +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; + /** + * @method: onCreate + * @description: 创建闹钟操作并控制闹钟设置界面 + * @date: 2023/12/23 10:50 + * @author: wyf + * @param: bundle + * @return: void + */ + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_NO_TITLE);//界面显示——无标题 + final Window win = getWindow(); + win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); + + if (!isScreenOn()) { + win.addFlags( + WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON//保持窗体点亮 + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON//将窗体点亮 + | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON//允许窗体点亮时锁屏 + | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); //在手机锁屏后如果到了闹钟提示时间,点亮屏幕 + } + + Intent intent = getIntent(); + + try { + mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); //根据ID从数据库中获取标签的内容,getContentResolver()是实现数据共享,实例存储。 + 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; //判断标签片段是否达到符合长度 + } + //异常处理:try如果有错误,就会返回所写异常的处理。 + catch (IllegalArgumentException e) { + e.printStackTrace(); + return; + } + mPlayer = new MediaPlayer(); + if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { + showActionDialog();//弹出对话框 + playAlarmSound();//闹钟提示音激发 + } else { + finish();//完成闹钟动作 + } + } + /** + * @method: isScreenOn + * @description: 判断是否锁屏 + * @date: 2023/12/23 10:56 + * @author: wyf + * @param: null + * @return: void + */ + private boolean isScreenOn() { + //判断屏幕是否锁屏,调用系统函数判断,最后返回值是布尔类型 + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + return pm.isScreenOn(); + } + /** + * @method playAlarmSound + * @description: 播放闹钟提示音 + * @date: 2023/12/23 10:58 + * @author: wyf + * @param: null + * @return: void + */ + private void playAlarmSound() { + Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);//调用系统的铃声管理URI,得到闹钟提示音 + + int silentModeStreams = Settings.System.getInt(getContentResolver(), + Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0); + + if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) { + mPlayer.setAudioStreamType(silentModeStreams); + } else { + mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); + } + try { + mPlayer.setDataSource(this, url);//解释:无返回值,设置多媒体数据来源【根据 Uri】 + mPlayer.prepare();//准备同步 + mPlayer.setLooping(true);//设置是否循环播放 + mPlayer.start();//开始播放 + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace();//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(); + } + } + /** + * @method showActionDialog + * @description 设置对话框 + * @date: 2023/12/23 11:13 + * @author: wyf + * @param: null + * @return: void + */ + private void showActionDialog() { + //AlertDialog的构造方法全部是Protected的 + //所以不能直接通过new一个AlertDialog来创建出一个AlertDialog。 + //要创建一个AlertDialog,就要用到AlertDialog.Builder中的create()方法 + //如这里的dialog就是新建了一个AlertDialog + AlertDialog.Builder dialog = new AlertDialog.Builder(this); + dialog.setTitle(R.string.app_name);//为对话框设置标题 + dialog.setMessage(mSnippet); //为对话框设置内容 + dialog.setPositiveButton(R.string.notealert_ok, this);//给对话框添加"Yes"按钮 + if (isScreenOn()) { + dialog.setNegativeButton(R.string.notealert_enter, this);//对话框添加"No"按钮 + } + dialog.show().setOnDismissListener(this); + } + /** + * @method onClick + * @description 确定点击后的动作 + * @date: 2023/12/23 11:18 + * @author: wyf + * @param: interface\int + * @return: void + */ + public void onClick(DialogInterface dialog, int which) { + switch (which) {//用which来选择click后下一步的操作 + case DialogInterface.BUTTON_NEGATIVE://取消操作 + Intent intent = new Intent(this, NoteEditActivity.class); //实现两个类间的数据传输 + intent.setAction(Intent.ACTION_VIEW);//设置动作属性 + intent.putExtra(Intent.EXTRA_UID, mNoteId);//实现key-value对,EXTRA_UID为key;mNoteId为键 + startActivity(intent);//开始动作 + break; + default: + break; + } + } + /** + * @method onDismiss + * @description 关闭闹钟 + * @date: 2023/12/23 11:17 + * @author: wyf + * @param: interface + * @return: void + */ + public void onDismiss(DialogInterface dialog) { + stopAlarmSound(); //停止闹钟声音 + finish();//完成该动作 + } + /** + * @method stopAlarmSound + * @description 停止闹钟声音 + * @date: 2023/12/23 11:20 + * @author: wyf + * @param: null + * @return: void + */ + private void stopAlarmSound() { + if (mPlayer != null) { + mPlayer.stop();//停止播放 + mPlayer.release();//释放MediaPlayer对象 + mPlayer = null; + } + } +} diff --git a/src/model/AlarmInitReceiver.java b/src/model/AlarmInitReceiver.java new file mode 100644 index 0000000..28e9246 --- /dev/null +++ b/src/model/AlarmInitReceiver.java @@ -0,0 +1,82 @@ +/* + * 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 android.os.Bundle; + +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; + +/** + * @ProjectName: Alarm + * @Package: net.micode.notes.ui + * @ClassName: AlarmInitReceiver + * @Description: 确定时间,构建闹钟 + * @Author: wyf + * @CreateDate: 2023/12/24 16:53 + */ +public class AlarmInitReceiver extends BroadcastReceiver { + //对数据库的操作,调用标签ID和闹钟时间 + 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; + /** + * @method: onReceive + * @description:获取闹钟时间并创建闹钟 + * @date: 2023/12/24 17:23 + * @author: wyf + * @param: class + * @return: void + */ + @Override + public void onReceive(Context context, Intent intent) { + long currentDate = System.currentTimeMillis();//System.currentTimeMillis()产生一个当前的毫秒,这个毫秒其实就是自1970年1月1日0时起的毫秒数 + //将long变量currentDate转化为字符串 + //Cursor在这里的作用是通过查找数据库中的标签内容,找到和当前系统时间相等的标签 + 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); + } while (c.moveToNext()); + } + c.close(); + } + } +} diff --git a/src/model/AlarmReceiver.java b/src/model/AlarmReceiver.java new file mode 100644 index 0000000..0d91473 --- /dev/null +++ b/src/model/AlarmReceiver.java @@ -0,0 +1,47 @@ +/* + * 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; +/** + * @ProjectName: Alarm + * @Package: net.micode.notes.ui + * @ClassName: AlarmReceiver + * @Description: 闹钟用户层的包 + * @Author: wyf + * @CreateDate: 2023/12/24 17:04 + */ +public class AlarmReceiver extends BroadcastReceiver { + @Override + /** + * @method: onReceive + * @description:启动闹钟程序 + * @date: 17:25 + * @author: wyf + * @param: class + * @return: void + */ + public void onReceive(Context context, Intent intent) { + //启动AlarmAlertActivity + intent.setClass(context, AlarmAlertActivity.class); + //新起一个栈装入启动的activity + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } +} diff --git a/src/model/DateTimePicker.java b/src/model/DateTimePicker.java new file mode 100644 index 0000000..18a58ef --- /dev/null +++ b/src/model/DateTimePicker.java @@ -0,0 +1,622 @@ +/* + * 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; +/** + * @ProjectName: DateTime + * @Package: net.micode.notes.ui + * @ClassName: DateTimePicker + * @Description: 对日期等数据模板进行初始化 + * @Author: wyf + * @CreateDate: 2023/12/24 17:06 + */ +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; + //NumberPicker是数字选择器 + //这里定义的四个变量全部是在设置闹钟时需要选择的变量(如日期、时、分、上午或者下午) + private final NumberPicker mDateSpinner; + private final NumberPicker mHourSpinner; + private final NumberPicker mMinuteSpinner; + private final NumberPicker mAmPmSpinner; + private Calendar mDate;//定义了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; //OnValueChangeListener,这是时间改变监听器,这里主要是对日期的监听 + private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() { + @Override + /** + * @method: onValueChange + * @description:获取日期信息 + * @date: 2023/12/24 17:15 + * @author: wyf + * @param: int + * @return: void + */ + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal); //将现在日期的值传递给mDate + updateDateControl();//updateDateControl是同步操作 + onDateTimeChanged(); + } + }; + //对小时(Hour)的监听 + private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() { + @Override + /** + * @method: onValueChange + * @description: + * @date: 2023/12/24 17:16 + * @author: wyf + * @param: class\int + * @return: void + */ + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + boolean isDateChanged = false; + //声明一个Calendar的变量cal,便于后续的操作 + Calendar cal = Calendar.getInstance(); + if (!mIs24HourView) { + //这里是对于12小时制时,晚上11点和12点交替时对日期的更改 + if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) { + cal.setTimeInMillis(mDate.getTimeInMillis()); + cal.add(Calendar.DAY_OF_YEAR, 1); + isDateChanged = true; + } + //这里是对于12小时制时,凌晨11点和12点交替时对日期的更改 + 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); + isDateChanged = true; + } + //这里是对于12小时制时,中午11点和12点交替时对AM和PM的更改 + if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY || + oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) { + mIsAm = !mIsAm; + updateAmPmControl(); + } + } else { + //这里是对于24小时制时,晚上11点和12点交替时对日期的更改 + if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) { + cal.setTimeInMillis(mDate.getTimeInMillis()); + cal.add(Calendar.DAY_OF_YEAR, 1); + isDateChanged = true; + } + //这里是对于12小时制时,凌晨11点和12点交替时对日期的更改 + 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);//通过数字选择器对newHour的赋值 + mDate.set(Calendar.HOUR_OF_DAY, newHour);//通过set函数将新的Hour值传给mDate + onDateTimeChanged(); + if (isDateChanged) { + setCurrentYear(cal.get(Calendar.YEAR)); + setCurrentMonth(cal.get(Calendar.MONTH)); + setCurrentDay(cal.get(Calendar.DAY_OF_MONTH)); + } + } + }; + //对分钟(Minute)改变的监听 + private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() { + @Override + /** + * @method: onValueChange + * @description:对分钟进行修改 + * @date: 2023/12/24 17:27 + * @author: wyf + * @param: class\int + * @return: void + */ + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + int minValue = mMinuteSpinner.getMinValue(); + int maxValue = mMinuteSpinner.getMaxValue(); + int offset = 0; //设置offset,作为小时改变的一个记录数据 + if (oldVal == maxValue && newVal == minValue) { + offset += 1; //如果原值为59,新值为0,则offset加1 + } else if (oldVal == minValue && newVal == maxValue) { + offset -= 1;//如果原值为0,新值为59,则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(); + } + }; + //对AM和PM的监听 + private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() { + @Override + /** + * @method: onValueChange + * @description:对AM和PM进行修改 + * @date: 2023/12/24 17:29 + * @author: wyf + * @param: class\int + * @return: void + */ + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + mIsAm = !mIsAm; + if (mIsAm) { + mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY); + } else { + mDate.add(Calendar.HOUR_OF_DAY, HOURS_IN_HALF_DAY); + } + 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));//得到的是一个天文数字(1970至今的秒数),需要DateFormat将其变得有意义 + } + + 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); + //如果当前Activity里用到别的layout,比如对话框layout + //还要设置这个layout上的其他组件的内容,就必须用inflate()方法先将对话框的layout找出来 + //然后再用findViewById()找到它上面的其它组件 + 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); + mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener); + + String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings(); + 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 + */ + /** + * @method: setCurrentDate + * @description:设置当前时间(以date为参数) + * @date: 2023/12/24 17:36 + * @author: wyf + * @param: long + * @return: void + */ + 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 + */ + /** + * @method: setCurrentDate + * @description:设置当前时间(以各项数据为参数) + * @date: 2023/12/24 17:39 + * @author: wyf + * @param: int + * @return: void + */ + 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); + }//得到year、month、day等值 + /** + * Set current year + * + * @param year The current year + */ + /** + * @method: setCurrentYear + * @description:设置年的数据 + * @date: 2023/12/24 17:45 + * @author: wyf + * @param: int + * @return: void + */ + 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 + */ + /** + * @method: setCurrentMonth + * @description:设置月的数据 + * @date: 2023/12/24 17:47 + * @author: wyf + * @param: int + * @return: void + */ + 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 + */ + /** + * @method: setCurrentDay + * @description:设置日的数据 + * @date: 2023/12/24 17:48 + * @author: wyf + * @param: int + * @return: void + */ + 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){ + return getCurrentHourOfDay(); + } else { + int hour = getCurrentHourOfDay(); + if (hour > HOURS_IN_HALF_DAY) { + 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 + */ + /** + * @method: getCurrentHour + * @description:设置小时的数据 + * @date: 2023/12/24 17:48 + * @author: wyf + * @param: int + * @return: void + */ + public void setCurrentHour(int hourOfDay) { + if (!mInitialising && hourOfDay == getCurrentHourOfDay()) { + return; + } + mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); + if (!mIs24HourView) { + if (hourOfDay >= HOURS_IN_HALF_DAY) { + mIsAm = false; + if (hourOfDay > HOURS_IN_HALF_DAY) { + 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 + */ + /** + * @method: setCurrentMinute + * @description:设置当前分钟数 + * @date: 2023/12/24 17:51 + * @author: wyf + * @param: int + * @return: void + */ + 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; + } + + /** + * Set whether in 24 hour or AM/PM mode. + * + * @param is24HourView True for 24 hour mode. False for AM/PM mode. + */ + /** + * @method: set24HourView + * @description:设置24小时数据 + * @date: 2023/12/24 17:52 + * @author: wyf + * @param: boolean + * @return: void + */ + public void set24HourView(boolean is24HourView) { + if (mIs24HourView == is24HourView) { + return; + } + mIs24HourView = is24HourView; + mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE); + int hour = getCurrentHourOfDay(); + updateHourControl(); + setCurrentHour(hour); + updateAmPmControl(); + } + /** + * @method: updateDateControl + * @description:计算是星期几 + * @date: 2023/12/24 17:53 + * @author: wyf + * @param: null + * @return: void + */ + 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); + 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); + } + mDateSpinner.setDisplayedValues(mDateDisplayValues); + mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2); + mDateSpinner.invalidate(); + } + /** + * @method: updateAmPmControl + * @description:计算现在是上下午 + * @date: 2023/12/24 17:54 + * @author: wyf + * @param: null + * @return: void + */ + private void updateAmPmControl() { + if (mIs24HourView) { + mAmPmSpinner.setVisibility(View.GONE); + } + else { + int index = mIsAm ? Calendar.AM : Calendar.PM; + mAmPmSpinner.setValue(index); + mAmPmSpinner.setVisibility(View.VISIBLE); + } + } + /** + * @method: updateHourControl + * @description:计算时间的算法 + * @date: 2023/12/24 17:55 + * @author: wyf + * @param: null + * @return: void + */ + private void updateHourControl() { + if (mIs24HourView) { + mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW); + mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW); + } else { + mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW); + mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW); + } + } + + /** + * 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; + } + /** + * @method: onDateTimeChanged + * @description:及时更新时间 + * @date: 2023/12/24 17:56 + * @author: wyf + * @param: null + * @return: void + */ + private void onDateTimeChanged() { + if (mOnDateTimeChangedListener != null) { + mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(), + getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute()); + } + } +} diff --git a/src/model/DateTimePickerDialog.java b/src/model/DateTimePickerDialog.java new file mode 100644 index 0000000..347d6cc --- /dev/null +++ b/src/model/DateTimePickerDialog.java @@ -0,0 +1,126 @@ +/* + * 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; +/** + * @ProjectName: DateTime + * @Package: net.micode.notes.ui + * @ClassName: DateTimePickerDialog + * @Description: 初始化对时间日期操作的变量 + * @Author: wyf + * @CreateDate: 2023/12/24 20:02 + */ +public class DateTimePickerDialog extends AlertDialog implements OnClickListener { + + private Calendar mDate = Calendar.getInstance();//创建一个Calendar类型的变量 mDate,方便时间的操作 + private boolean mIs24HourView; + private OnDateTimeSetListener mOnDateTimeSetListener;//声明一个时间日期滚动选择控件 mOnDateTimeSetListener + private DateTimePicker mDateTimePicker; //DateTimePicker控件,控件一般用于让用户可以从日期列表中选择单个值。运行时,单击控件边上的下拉箭头,会显示为两个部分:一个下拉列表,一个用于选择日期的 + + 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); //将秒数设置为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()); + } + /** + * @method: set24HourView + * @description:实现时间标准化打印 + * @date: 2023/12/24 20:15 + * @author: wyf + * @param: boolean + * @return: void + */ + public void set24HourView(boolean is24HourView) { + mIs24HourView = is24HourView; + } + /** + * @method: setOnDateTimeSetListener + * @description:将时间日期滚动选择控件实例化 + * @date: 2023/12/24 20:14 + * @author: wyf + * @param: interface + * @return: void + */ + public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) { + mOnDateTimeSetListener = callBack; + } + /** + * @method: updateTitle + * @description:更新标题显示的时间日期 + * @date: 2023/12/24 20:15 + * @author: wyf + * @param: long + * @return: void + */ + 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; + setTitle(DateUtils.formatDateTime(this.getContext(), date, flag)); + } + /** + * @method: onClick + * @description:点击事件的对话框 + * @date: 2023/12/24 20:17 + * @author: wyf + * @param: interface\int + * @return: void + */ + public void onClick(DialogInterface arg0, int arg1) { + if (mOnDateTimeSetListener != null) { + mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); + } + } + +} \ No newline at end of file diff --git a/src/model/DropdownMenu.java b/src/model/DropdownMenu.java new file mode 100644 index 0000000..9a6a8a2 --- /dev/null +++ b/src/model/DropdownMenu.java @@ -0,0 +1,75 @@ +/* + * 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; +/** + * @ProjectName: DropdownMenu + * @Package: net.micode.notes.ui + * @ClassName: DropdownMenu + * @Description: 设置下滑菜单 + * @Author: wyf + * @CreateDate: 2023/12/24 20:20 + */ +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);//设置这个view的背景 + mPopupMenu = new PopupMenu(context, mButton); + mMenu = mPopupMenu.getMenu(); + mPopupMenu.getMenuInflater().inflate(menuId, mMenu);//MenuInflater是用来实例化Menu目录下的Menu布局文件,根据ID来确认menu的内容选项 + mButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + mPopupMenu.show(); + } + }); + } + /** + * @method: setOnDropdownMenuItemClickListener + * @description:设置下拉菜单的监听 + * @date: 2023/12/24 20:24 + * @author: wyf + * @param: interface + * @return: void + */ + 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); + }//布局文件,设置标题 +} diff --git a/src/model/FoldersListAdapter.java b/src/model/FoldersListAdapter.java new file mode 100644 index 0000000..ae8c08a --- /dev/null +++ b/src/model/FoldersListAdapter.java @@ -0,0 +1,112 @@ +/* + * 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; + +/** + * @ProjectName: FoldersListAdapter + * @Package: net.micode.notes.ui + * @ClassName: FoldersListAdapter + * @Description: 设置文件夹的控制变量 + * @Author: wyf + * @CreateDate: 2023/12/24 20:31 + */ +//CursorAdapter是Cursor和ListView的接口 +//FoldersListAdapter继承了CursorAdapter的类 +//主要作用是便签数据库和用户的交互 +//这里就是用folder(文件夹)的形式展现给用户 +public class FoldersListAdapter extends CursorAdapter { + 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);//创建一个文件夹,对于各文件夹中子标签的初始化 + } + /** + * @method: bindView + * @description:将各个布局文件绑定起来 + * @date: 2023/12/24 20:40 + * @author: wyf + * @param: class\interface + * @return: void + */ + @Override + public void bindView(View view, Context context, Cursor cursor) { + if (view instanceof 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; + /** + * @ProjectName: FolderListItem + * @Package: net.micode.notes.ui + * @ClassName: FolderListItem + * @Description: 设置文件夹各项目 + * @Author: wyf + * @CreateDate: 2023/12/24 20:42 + */ + public FolderListItem(Context context) { + super(context);//操作数据库 + inflate(context, R.layout.folder_list_item, this);//根据布局文件的名字等信息将其找出来 + mName = (TextView) findViewById(R.id.tv_folder_name); + } + /** + * @method: bind + * @description:设置显示名称 + * @date: 2023/12/24 20:46 + * @author: wyf + * @param: string + * @return: void + */ + public void bind(String name) { + mName.setText(name); + } + } + +} diff --git a/src/widget/NoteWidgetProvider.java b/src/widget/NoteWidgetProvider.java new file mode 100644 index 0000000..e2a74d9 --- /dev/null +++ b/src/widget/NoteWidgetProvider.java @@ -0,0 +1,132 @@ +/* + * 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.widget; +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.util.Log; +import android.widget.RemoteViews; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.tool.ResourceParser; +import net.micode.notes.ui.NoteEditActivity; +import net.micode.notes.ui.NotesListActivity; + +public abstract class NoteWidgetProvider extends AppWidgetProvider { //添加小米便签到安卓系统小部件 + public static final String [] PROJECTION = new String [] { + NoteColumns.ID, + NoteColumns.BG_COLOR_ID, + NoteColumns.SNIPPET + }; // 定义小部件的ID、背景颜色、列,包括42、43、44三行代码 + + public static final int COLUMN_ID = 0; + public static final int COLUMN_BG_COLOR_ID = 1; + public static final int COLUMN_SNIPPET = 2; + + private static final String TAG = "NoteWidgetProvider"; + + @Override //子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。 + public void onDeleted(Context context, int[] appWidgetIds) { //onDeleted在用户从桌面上删除小部件时被调用 + ContentValues values = new ContentValues(); + values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); + for (int i = 0; i < appWidgetIds.length; i++) { + context.getContentResolver().update(Notes.CONTENT_NOTE_URI, + values, + NoteColumns.WIDGET_ID + "=?", + new String[] { String.valueOf(appWidgetIds[i])}); + } + } //在小部件被删除时,更新数据库,将所有相关联的小部件ID标记为无效 + + private Cursor getNoteWidgetInfo(Context context, int widgetId) { + return context.getContentResolver().query(Notes.CONTENT_NOTE_URI, + PROJECTION, + NoteColumns.WIDGET_ID + "=? AND " + NoteColumns.PARENT_ID + "<>?", + new String[] { String.valueOf(widgetId), String.valueOf(Notes.ID_TRASH_FOLER) }, + null); + } // 获取小米便签小部件的信息 + + protected void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + update(context, appWidgetManager, appWidgetIds, false); + } //更新小米便签小部件信息 + + private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds, + boolean privacyMode) { + for (int i = 0; i < appWidgetIds.length; i++) {//遍历所有的小部件ID,然后更新每个小部件的视图和行为 + if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) { //判断是否无效小部件 + int bgId = ResourceParser.getDefaultBgId(context); + String snippet = ""; + Intent intent = new Intent(context, NoteEditActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetIds[i]); + intent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType()); + + Cursor c = getNoteWidgetInfo(context, appWidgetIds[i]); + if (c != null && c.moveToFirst()) { + if (c.getCount() > 1) { + Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]); + c.close(); + return; + } //将新数据放到数据表中 + snippet = c.getString(COLUMN_SNIPPET); + bgId = c.getInt(COLUMN_BG_COLOR_ID); + intent.putExtra(Intent.EXTRA_UID, c.getLong(COLUMN_ID)); + intent.setAction(Intent.ACTION_VIEW); + } else { + snippet = context.getResources().getString(R.string.widget_havenot_content); + intent.setAction(Intent.ACTION_INSERT_OR_EDIT);//点击事件。没有检测到关联的小部件,点击创建 + } + + if (c != null) { + c.close(); + } //关闭游标 + + RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId()); + rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId)); + intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId); + /** + * 生成待处理的 intent 以启动小组件的主机 + */ + PendingIntent pendingIntent = null;// 新建点击程序 + if (privacyMode) { + rv.setTextViewText(R.id.widget_text, + context.getString(R.string.widget_under_visit_mode)); + pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], new Intent( + context, NotesListActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);// 提示处于访客模式,创建新的intent变量记录活动 + } else { + rv.setTextViewText(R.id.widget_text, snippet); + pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], intent, + PendingIntent.FLAG_UPDATE_CURRENT);//直接使用已有intent记录活动 + } + + rv.setOnClickPendingIntent(R.id.widget_text, pendingIntent); //为小部件文本视图设置点击程序 + appWidgetManager.updateAppWidget(appWidgetIds[i], rv); // 更新小部件视图 + } + } + } + + protected abstract int getBgResourceId(int bgId);//获取背景资源的ID + + protected abstract int getLayoutId();//获取布局文件的资源ID + + protected abstract int getWidgetType();//获取小部件ID +} diff --git a/src/widget/NoteWidgetProvider_2x.java b/src/widget/NoteWidgetProvider_2x.java new file mode 100644 index 0000000..876c305 --- /dev/null +++ b/src/widget/NoteWidgetProvider_2x.java @@ -0,0 +1,47 @@ +/* + * 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.widget; + +import android.appwidget.AppWidgetManager; +import android.content.Context; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.tool.ResourceParser; + + +public class NoteWidgetProvider_2x extends NoteWidgetProvider {//扩展 + @Override + public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + super.update(context, appWidgetManager, appWidgetIds);//重写二倍大小小部件的更新函数 + } + + @Override + protected int getLayoutId() { + return R.layout.widget_2x; + }//重写两倍大小小部件的布局文件的资源ID + + @Override + protected int getBgResourceId(int bgId) { + return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId);//重写两倍大小小部件的背景资源的ID + } + + @Override + protected int getWidgetType() { + return Notes.TYPE_WIDGET_2X; + }//重写两倍大小小部件的小部件类型 +} diff --git a/src/widget/NoteWidgetProvider_4x.java b/src/widget/NoteWidgetProvider_4x.java new file mode 100644 index 0000000..10c3bb9 --- /dev/null +++ b/src/widget/NoteWidgetProvider_4x.java @@ -0,0 +1,46 @@ +/* + * 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.widget; + +import android.appwidget.AppWidgetManager; +import android.content.Context; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.tool.ResourceParser; + + +public class NoteWidgetProvider_4x extends NoteWidgetProvider {//扩展 + @Override + public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + super.update(context, appWidgetManager, appWidgetIds);//重写四倍大小小部件的更新函数 + } + + protected int getLayoutId() { + return R.layout.widget_4x; + }//重写四倍大小小部件的布局文件的资源ID + + @Override + protected int getBgResourceId(int bgId) { + return ResourceParser.WidgetBgResources.getWidget4xBgResource(bgId);//重写四倍大小小部件的背景资源的ID + } + + @Override + protected int getWidgetType() { + return Notes.TYPE_WIDGET_4X; + }//重写四倍大小小部件的小部件类型 +}