diff --git a/.gitignore b/.gitignore
index e3879fd..8b82a29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
/src/Notes/
/src/.idea/
-/src/Notes-master1/
+/src/Notes/
/.idea/
diff --git a/doc/小米便签质量分析报告.docx b/doc/小米便签质量分析报告.docx
index 4d17085..f4c7061 100644
Binary files a/doc/小米便签质量分析报告.docx and b/doc/小米便签质量分析报告.docx differ
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index b6036d7..3b7012e 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -1,25 +1,56 @@
+
+
+
+
+ android:versionName="0.1" >
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+ android:icon="@drawable/icon_app"
+ android:label="@string/app_name"
+ android:requestLegacyExternalStorage="true">
-
+
+ android:windowSoftInputMode="adjustPan" >
+
+
+
+
+
-
+
+ android:theme="@style/NoteTheme" >
-
+
-
-
+
-
+
-
-
+
-
+
-
-
+
-
+
+
+
+ android:multiprocess="true" />
+
+
+ android:label="@string/app_widget2x2" >
-
+
-
+
+ android:label="@string/app_widget4x4" >
-
+
-
+
-
-
+
+
+
+
-
+
+
+
+ android:name="net.micode.notes.ui.AlarmReceiver"
+ android:process=":remote" >
+
+
+
+ android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" >
+
+
+
+ android:theme="@android:style/Theme.Holo.Light" >
+
+
+
+ android:name="net.micode.notes.gtask.remote.GTaskSyncService"
+ android:exported="false" >
+
+
+
-
-
\ No newline at end of file
+
diff --git a/src/main/java/net/micode/notes/ui/NoteEditActivity.java b/src/main/java/net/micode/notes/ui/NoteEditActivity.java
index 0ad5f86..b740b4a 100644
--- a/src/main/java/net/micode/notes/ui/NoteEditActivity.java
+++ b/src/main/java/net/micode/notes/ui/NoteEditActivity.java
@@ -38,6 +38,8 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.core.app.ActivityCompat;
+
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.TextNote;
@@ -114,6 +116,12 @@ public class NoteEditActivity extends Activity implements OnClickListener,
sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select);
}
+ public static final int PHOTO_REQUEST = 1;//添加图片
+ private static final int REQUEST_EXTERNAL_STORAGE=1;//权限申请
+ private static String[] PERMISSIONS_STORAGE = {
+ "android.permission.READ_EXTERNAL_STORAGE",
+ "android.permission.WRITE_EXTERNAL_STORAGE" };//权限名称
+
private static final String TAG = "NoteEditActivity";
private HeadViewHolder mNoteHeaderHolder;
private View mHeadViewPanel;
@@ -136,7 +144,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private String mUserQuery;
private Pattern mPattern;
-
+
/**
* @method Textchange
* @description 对原始文本进行处理,去除图片字符、换行符和空格字符
@@ -212,7 +220,23 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return;
}
initResources();
- count();
+
+ final ImageButton add_img_btn = (ImageButton) findViewById(R.id.add_img_btn);//根据id获取添加图片按钮
+ //为点击图片按钮设置监听器
+ add_img_btn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Log.d(TAG, "onClick: click add image button");
+ //ACTION_GET_CONTENT: 允许用户选择特殊种类的数据,并返回(特殊种类的数据:照一张相片或录一段音)
+ Intent loadImage = new Intent(Intent.ACTION_GET_CONTENT);
+ //Category属性用于指定当前动作(Action)被执行的环境.
+ //CATEGORY_OPENABLE; 用来指示一个ACTION_GET_CONTENT的intent
+ loadImage.addCategory(Intent.CATEGORY_OPENABLE);
+ loadImage.setType("image/*");
+ startActivityForResult(loadImage, PHOTO_REQUEST);
+ }
+ });
+ convertToImage();//将路径显示为图片
}
/**
@@ -356,6 +380,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* is not ready
*/
showAlertHeader();
+ convertToImage();//将路径转化未图片
}
/**
* @method showAlertHeader
@@ -1050,4 +1075,221 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private void showToast(int resId, int duration) {
Toast.makeText(this, resId, duration).show();
}
+
+ /**
+ * @method convertToImage
+ * @description: 路径字符串格式 转换为 图片image格式
+ * @date: 2024/1/3 19:19
+ * @author: WuShuxian
+ * @param: void
+ * @return: void
+ */
+ private void convertToImage() {
+ NoteEditText noteEditText = (NoteEditText) findViewById(R.id.note_edit_view); //获取当前的edit
+ Editable editable = noteEditText.getText();//1.获取text
+ String noteText = editable.toString(); //2.将note内容转换为字符串
+ int length = editable.length(); //内容的长度
+ //3.截取img片段 [local]+uri+[/local],提取uri。算法效率有待改善可以考虑KMP
+ for(int i = 0; i < length; i++) {
+ for(int j = i; j < length; j++) {
+ String img_fragment = noteText.substring(i, j+1); //img_fragment:关于图片路径的片段
+ if(img_fragment.length() > 15 && img_fragment.endsWith("[/local]") &&
+ img_fragment.startsWith("[local]")){
+ int limit = 7; //[local]为7个字符
+ int len = img_fragment.length()-15;//[local][/local]共15个字符,剩下的为真正的path长度
+ String path = img_fragment.substring(limit,limit+len);//获取到了图片路径从[local]之后的len个字符就是path
+ Bitmap bitmap = null;
+ Log.d(TAG, "图片的路径是:"+path);
+ try {
+ bitmap = BitmapFactory.decodeFile(path);//将图片路径解码为图片格式
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ //若图片存在
+ if(bitmap!=null){
+ Log.d(TAG, "图片不为null");
+ ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
+ String ss = "[local]" + path + "[/local]";
+ SpannableString spannableString = new SpannableString(ss);//4.创建一个SpannableString对象,以便插入用ImageSpan对象封装的图像
+
+ spannableString.setSpan(imageSpan, 0, ss.length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//5.将指定的标记对象附加到文本的开始...结束范围
+ Log.d(TAG, "Create spannable string success!");
+ Editable edit_text = noteEditText.getEditableText();
+ edit_text.delete(i,i+len+15); //6.删掉图片路径的文字
+ edit_text.insert(i, spannableString); //7.在路径的起始位置插入图片
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @method onActivityResult
+ * @description: 插入图片时:重写onActivityResult()来处理返回的数据,点击插入图片返回后执行
+ * @date: 2024/1/3 19:20
+ * @author: WuShuxian
+ * @param:
+ * @return: void
+ */
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ super.onActivityResult(requestCode, resultCode, intent);
+ ContentResolver resolver = getContentResolver();
+ switch (requestCode) {
+ case PHOTO_REQUEST:
+ Uri originalUri = intent.getData(); //1.获得图片的真实路径
+ Bitmap bitmap = null;
+ try {
+ bitmap = BitmapFactory.decodeStream(resolver.openInputStream(originalUri));//2.解码图片
+ } catch (FileNotFoundException e) {
+ Log.d(TAG, "onActivityResult: get file_exception");
+ e.printStackTrace();
+ }
+ //3.根据Bitmap对象创建ImageSpan对象
+ if(bitmap != null){
+ Log.d(TAG, "onActivityResult: bitmap is not null");
+ ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
+ String path = getPath(this,originalUri);
+ String img_fragment= "[local]" + path + "[/local]";//4.使用[local][/local]将path括起来,用于之后方便识别图片路径在note中的位置
+ SpannableString spannableString = new SpannableString(img_fragment);//创建一个SpannableString对象,以便插入用ImageSpan对象封装的图像
+ spannableString.setSpan(imageSpan, 0,
+ img_fragment.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ NoteEditText e = (NoteEditText) findViewById(R.id.note_edit_view);//5.将选择的图片追加到EditText中光标所在位置
+ int index = e.getSelectionStart(); //获取光标所在位置
+ Log.d(TAG, "Index是: " + index);
+ Editable edit_text = e.getEditableText();
+ edit_text.insert(index, spannableString); //将图片插入到光标所在位置
+
+ mWorkingNote.setWorkingText(e.getText().toString());
+ //6.把改动提交到数据库中,两个数据库表都要改的
+ ContentResolver contentResolver = getContentResolver();
+ ContentValues contentValues = new ContentValues();
+ final long id = mWorkingNote.getNoteId();
+ contentValues.put("snippet",mWorkingNote.getContent());
+ contentResolver.update(Uri.parse("content://micode_notes/note"),
+ contentValues,"_id=?",new String[]{""+id});
+ ContentValues contentValues1 = new ContentValues();
+ contentValues1.put("content",mWorkingNote.getContent());
+ contentResolver.update(Uri.parse("content://micode_notes/data"),
+ contentValues1,"mime_type=? and note_id=?",
+ new String[]{"vnd.android.cursor.item/text_note",""+id});
+
+ }else{
+ Toast.makeText(NoteEditActivity.this, "获取图片失败", Toast.LENGTH_SHORT).show();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * @method getPath
+ * @description: 获取文件的real path
+ * @date: 2024/1/3 19:22
+ * @author: WuShuxian
+ * @param:
+ * @return:
+ */
+ public String getPath(final Context context, final Uri uri) {
+
+ final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+
+ // DocumentProvider
+ if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
+ if (isMediaDocument(uri)) {
+ final String docId = DocumentsContract.getDocumentId(uri);
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ Uri contentUri = null;
+ if ("image".equals(type)) {
+ contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ }
+
+ final String selection = "_id=?";
+ final String[] selectionArgs = new String[]{split[1]};
+
+ return getDataColumn(context, contentUri, selection, selectionArgs);
+ }
+ }
+ // Media
+ else if ("content".equalsIgnoreCase(uri.getScheme())) {
+ return getDataColumn(context, uri, null, null);
+ }
+ // File
+ else if ("file".equalsIgnoreCase(uri.getScheme())) {
+ return uri.getPath();
+ }
+ return null;
+ }
+
+ /**
+ * @method isMediaDocument
+ * @description: 判断是否为媒体文件
+ * @date: 2024/1/3 19:23
+ * @author: WuShuxian
+ * @param: uri
+ * @return:
+ */
+ public boolean isMediaDocument(Uri uri) {
+ return "com.android.providers.media.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @method getDataColumn
+ * @description: 获取数据列_获取此 Uri 的数据列的值。这对MediaStore Uris 和其他基于文件的 ContentProvider。
+ * @date: 2024/1/3 19:23
+ * @author: WuShuxian
+ * @param:
+ * @return:
+ */
+ public String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
+
+ Cursor cursor = null;
+ final String column = "_data";
+ final String[] projection = {column};
+
+ try {
+ cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ final int column_index = cursor.getColumnIndexOrThrow(column);
+ return cursor.getString(column_index);
+ }
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+ return null;
+ }
+
+ /**
+ * @method checkStoragePermissions
+ * @description: 用于动态申请权限
+ * @date: 2024/1/6 8:58
+ * @author: WuShuxian
+ * @param: activity
+ * @return: void
+ */
+ public static void checkStoragePermissions(Activity activity){
+ try{
+ //监测是否有写/读的权限
+ int permission= ActivityCompat.checkSelfPermission(activity,
+ "android.permission.WRITE_EXTERNAL_STORAGE");
+ int permission1= ActivityCompat.checkSelfPermission(activity,
+ "android.permission.READ_EXTERNAL_STORAGE");
+ if(permission != PackageManager.PERMISSION_GRANTED){
+ //没有写的权限,去申请写的权限,或弹出对话框
+ ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
+ }
+ if(permission1 != PackageManager.PERMISSION_GRANTED){
+ //没有读的权限,去申请读的权限,或弹出对话框
+ ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
+ }
+
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ }
}
diff --git a/src/main/res/drawable-hdpi/ic_menu_gallery_new.png b/src/main/res/drawable-hdpi/ic_menu_gallery_new.png
new file mode 100644
index 0000000..863c493
Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_menu_gallery_new.png differ
diff --git a/src/main/res/layout/note_edit.xml b/src/main/res/layout/note_edit.xml
index 59415d7..defd4eb 100644
--- a/src/main/res/layout/note_edit.xml
+++ b/src/main/res/layout/note_edit.xml
@@ -405,4 +405,13 @@
android:src="@drawable/selected" />
+
+
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 469b04c..dccf596 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -39,6 +39,7 @@
notes_%s.txt
(%d)
+ Add picture
New Folder
Export text
Sync