功能维护--增加插入图片的功能

文档统一
master
SheYu 11 months ago
parent 45ccee3d86
commit 2532958700

@ -1,25 +1,57 @@
<?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"
package="net.micode.notes"
android:versionCode="1"
android:versionName="0.1"> <!-- - 指定应用程序需要支持的最低的 Android SDK 版本 -->
android:versionName="0.1" >
<!--- 指定应用程序需要支持的最低的 Android SDK 版本 -->
<uses-sdk android:minSdkVersion="14" />
<!-- - 权限声明 -->
<!-- - 写入 SD 卡的权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- - 创建、删除有关快捷方式的权限 -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /> <!-- - 访问网络的权限 -->
<uses-permission android:name="android.permission.INTERNET" /> <!-- - 读取联系人的权限 -->
<uses-permission android:name="android.permission.READ_CONTACTS" /> <!-- - 账户管理的权限 -->
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> <!-- - 验证账户的权限 -->
<!--- 权限声明 -->
<!--- 写入 SD 卡的权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--- 创建、删除有关快捷方式的权限 -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!--- 访问网络的权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!--- 读取联系人的权限 -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<!--- 账户管理的权限 -->
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<!--- 验证账户的权限 -->
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" /> <!-- - 开机自动运行权限 -->
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<!--- 开机自动运行权限 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!--- 存储的读写权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--- 应用程序组件声明 -->
<!--- 定义应用程序的图标和名称 -->
<application
android:icon="@drawable/icon_app_1"
android:label="@string/app_name">
android:icon="@drawable/icon_app"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true">
<activity
android:name=".ui.SplashActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
@ -31,125 +63,139 @@
</intent-filter>
</activity>
<!-- - 应用程序的入口 NotesListActivity -->
<!--- 应用程序的入口 NotesListActivity -->
<activity
android:name=".ui.NotesListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/NoteTheme"
android:windowSoftInputMode="adjustPan">
android:windowSoftInputMode="adjustPan" >
<!--- 定义该 Activity 为启动器,即默认启动的 Activity -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- - 笔记编辑 Activity -->
<!--- 笔记编辑 Activity -->
<activity
android:name=".ui.NoteEditActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:launchMode="singleTop"
android:theme="@style/NoteTheme">
android:theme="@style/NoteTheme" >
<!-- - 笔记编辑 Activity 的 Intent Filter用于接收其他应用程序发送过来的消息 -->
<!--- 笔记编辑 Activity 的 Intent Filter用于接收其他应用程序发送过来的消息 -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<!-- - 笔记编辑 Activity 可以处理的 MIME 类型 -->
<data
android:host="com.example.notes.provider"
android:mimeType="vnd.android.cursor.item/text_note"
android:path="/notes"
android:scheme="content" />
<data
android:host="com.example.notes.provider"
android:mimeType="vnd.android.cursor.item/call_note"
android:path="/notes"
android:scheme="content" />
<!--- 笔记编辑 Activity 可以处理的 MIME 类型 -->
<data android:mimeType="vnd.android.cursor.item/text_note" android:scheme="content" android:host="com.example.notes.provider" android:path="/notes" />
<data android:mimeType="vnd.android.cursor.item/call_note" android:scheme="content" android:host="com.example.notes.provider" android:path="/notes" />
</intent-filter>
<!-- - 笔记编辑 Activity 的 Intent Filter用于接收其他应用程序发送过来的消息 -->
<!--- 笔记编辑 Activity 的 Intent Filter用于接收其他应用程序发送过来的消息 -->
<intent-filter>
<action android:name="android.intent.action.INSERT_OR_EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<!-- - 笔记编辑 Activity 可以处理的 MIME 类型 -->
<!--- 笔记编辑 Activity 可以处理的 MIME 类型 -->
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
<!-- - 搜索 Intent Filter用于响应搜索请求 -->
<!--- 搜索 Intent Filter用于响应搜索请求 -->
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<!-- - 搜索框的配置信息 -->
<!--- 搜索框的配置信息 -->
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity> <!-- - 笔记供应器,用于共享笔记数据 -->
</activity>
<!--- 笔记供应器,用于共享笔记数据 -->
<provider
android:name=".data.NotesProvider"
android:name="net.micode.notes.data.NotesProvider"
android:authorities="micode_notes"
android:multiprocess="true" /> <!-- - 笔记小部件,支持两种大小 -->
android:multiprocess="true" />
<!--- 笔记小部件,支持两种大小 -->
<receiver
android:name=".widget.NoteWidgetProvider_2x"
android:label="@string/app_widget2x2">
android:label="@string/app_widget2x2" >
<!-- - 笔记小部件的 Intent Filter用于接收系统广播和小部件更新操作 -->
<!--- 笔记小部件的 Intent Filter用于接收系统广播和小部件更新操作 -->
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
</intent-filter>
<!-- - 笔记小部件的配置信息 -->
<!--- 笔记小部件的配置信息 -->
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_2x_info" />
</receiver>
<receiver
android:name=".widget.NoteWidgetProvider_4x"
android:label="@string/app_widget4x4">
android:label="@string/app_widget4x4" >
<!-- - 笔记小部件的 Intent Filter用于接收系统广播和小部件更新操作 -->
<!--- 笔记小部件的 Intent Filter用于接收系统广播和小部件更新操作 -->
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
</intent-filter>
<!-- - 笔记小部件的配置信息 -->
<!--- 笔记小部件的配置信息 -->
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_4x_info" />
</receiver> <!-- - 启动时需要初始化闹钟服务 -->
<receiver android:name=".ui.AlarmInitReceiver">
</receiver>
<!--- 启动时需要初始化闹钟服务 -->
<receiver android:name=".ui.AlarmInitReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver> <!-- - 闹钟服务 -->
</receiver>
<!--- 闹钟服务 -->
<receiver
android:name=".ui.AlarmReceiver"
android:process=":remote"></receiver> <!-- - 闹钟提示 Activity -->
android:name="net.micode.notes.ui.AlarmReceiver"
android:process=":remote" >
</receiver>
<!--- 闹钟提示 Activity -->
<activity
android:name=".ui.AlarmAlertActivity"
android:label="@string/app_name"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar"></activity> <!-- - 首选项 Activity -->
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" >
</activity>
<!--- 首选项 Activity -->
<activity
android:name=".ui.NotesPreferenceActivity"
android:name="net.micode.notes.ui.NotesPreferenceActivity"
android:label="@string/preferences_title"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Holo.Light"></activity> <!-- - GTask 同步服务 -->
android:theme="@android:style/Theme.Holo.Light" >
</activity>
<!--- GTask 同步服务 -->
<service
android:name=".gtask.remote.GTaskSyncService"
android:exported="false"></service> <!-- - 默认搜索 Activity -->
android:name="net.micode.notes.gtask.remote.GTaskSyncService"
android:exported="false" >
</service>
<!--- 默认搜索 Activity -->
<meta-data
android:name="android.app.default_searchable"
android:value=".ui.NoteEditActivity" />
</application>
</manifest>
</manifest>

@ -136,7 +136,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private String mUserQuery;
private Pattern mPattern;
/**
* @method Textchange
* @description
@ -212,7 +212,6 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return;
}
initResources();
count();
}
/**
@ -1050,4 +1049,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();
}
}
}

@ -405,4 +405,13 @@
android:src="@drawable/selected" />
</FrameLayout>
</LinearLayout>
<ImageButton
android:id="@+id/add_img_btn"
android:layout_width="51dp"
android:layout_height="54dp"
android:layout_marginLeft="7dp"
android:layout_marginTop="600dp"
android:layout_marginBottom="7dp"
android:src="@drawable/ic_menu_gallery_new" />
</FrameLayout>

@ -39,6 +39,7 @@
<string name="file_name_txt_format">notes_%s.txt</string>
<!-- notes list string -->
<string name="format_folder_files_count">(%d)</string>
<string name="add_img_btn">Add picture</string>
<string name="menu_create_folder">New Folder</string>
<string name="menu_export_text">Export text</string>
<string name="menu_sync">Sync</string>

Loading…
Cancel
Save