@ -22,19 +22,35 @@ import android.app.AlertDialog;
import android.app.PendingIntent ;
import android.app.SearchManager ;
import android.appwidget.AppWidgetManager ;
import android.content.ContentResolver ;
import android.content.ContentUris ;
import android.content.ContentValues ;
import android.content.Context ;
import android.content.DialogInterface ;
import android.content.Intent ;
import android.content.SharedPreferences ;
import android.database.Cursor ;
import android.graphics.Bitmap ;
import android.graphics.BitmapFactory ;
import android.graphics.Matrix ;
import android.graphics.Paint ;
import android.graphics.drawable.BitmapDrawable ;
import android.graphics.drawable.Drawable ;
import android.net.Uri ;
import android.os.Build ;
import android.os.Bundle ;
import android.os.Environment ;
import android.preference.PreferenceManager ;
import android.provider.DocumentsContract ;
import android.provider.MediaStore ;
import android.support.v7.app.AppCompatActivity ;
import android.text.Editable ;
import android.text.Spannable ;
import android.text.SpannableString ;
import android.text.TextUtils ;
import android.text.format.DateUtils ;
import android.text.style.BackgroundColorSpan ;
import android.text.style.ImageSpan ;
import android.util.Log ;
import android.view.LayoutInflater ;
import android.view.Menu ;
@ -43,10 +59,12 @@ import android.view.MotionEvent;
import android.view.View ;
import android.view.View.OnClickListener ;
import android.view.WindowManager ;
import android.widget.Button ;
import android.widget.CheckBox ;
import android.widget.CompoundButton ;
import android.widget.CompoundButton.OnCheckedChangeListener ;
import android.widget.EditText ;
import android.widget.ImageButton ;
import android.widget.ImageView ;
import android.widget.LinearLayout ;
import android.widget.TextView ;
@ -65,6 +83,7 @@ import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener;
import net.micode.notes.widget.NoteWidgetProvider_2x ;
import net.micode.notes.widget.NoteWidgetProvider_4x ;
import java.io.FileNotFoundException ;
import java.util.HashMap ;
import java.util.HashSet ;
import java.util.Map ;
@ -72,7 +91,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern ;
public class NoteEditActivity extends A ctivity implements OnClickListener ,
public class NoteEditActivity extends A ppCompatA ctivity implements OnClickListener ,
NoteSettingChangedListener , OnTextViewChangeListener {
private class HeadViewHolder {
public TextView tvModified ;
@ -149,6 +168,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private String mUserQuery ;
private Pattern mPattern ;
private final int PHOTO_REQUEST = 1 ; //请求码
@Override
protected void onCreate ( Bundle savedInstanceState ) {
super . onCreate ( savedInstanceState ) ;
@ -159,12 +180,115 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return ;
}
initResources ( ) ;
//声明一个图片按钮, 并将布局中的图片加载到图片按钮中
final ImageButton add_img_btn = ( ImageButton ) findViewById ( R . id . add_img_btn ) ;
//设置监听器
add_img_btn . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View view ) {
//声明一个请求对象, 设置参数ACTION_GET_CONTENT: 允许用户选择特殊种类的数据(照片),并返回
Intent loadImage = new Intent ( Intent . ACTION_GET_CONTENT ) ;
//Category属性用于指定一个用途, 用于过滤
loadImage . addCategory ( Intent . CATEGORY_OPENABLE ) ;
//指定获取的是图片
loadImage . setType ( "image/*" ) ;
//打开相册
startActivityForResult ( loadImage , PHOTO_REQUEST ) ;
}
} ) ;
}
/ * *
* 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
//重写onActivityResult()来将图片插入便签中
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 ( ) ; //获得图片的真实路径
Bitmap bitmap = null ;
try {
bitmap = BitmapFactory . decodeStream ( resolver . openInputStream ( originalUri ) ) ; //解码图片
} catch ( FileNotFoundException e ) {
e . printStackTrace ( ) ;
}
if ( bitmap ! = null ) {
//根据Bitmap对象创建ImageSpan对象
ImageSpan imageSpan = new ImageSpan ( NoteEditActivity . this , bitmap ) ;
String path = getPath ( this , originalUri ) ;
Log . d ( TAG , path ) ;
//使用[local][/local]将path括起来, 用于之后方便识别图片路径在note中的位置
String img_fragment = "[local]" + path + "[/local]" ;
//创建一个SpannableString对象, 以便插入用ImageSpan对象封装的图像
SpannableString spannableString = new SpannableString ( img_fragment ) ;
spannableString . setSpan ( imageSpan , 0 , img_fragment . length ( ) , Spannable . SPAN_EXCLUSIVE_EXCLUSIVE ) ;
//将选择的图片追加到EditText中光标所在位置
NoteEditText e = ( NoteEditText ) findViewById ( R . id . note_edit_view ) ;
int index = e . getSelectionStart ( ) ; //获取光标所在位置
Log . d ( TAG , "Index是: " + index ) ;
Editable edit_text = e . getEditableText ( ) ;
edit_text . insert ( index , spannableString ) ; //将图片插入到光标所在位置
mWorkingNote . mContent = e . getText ( ) . toString ( ) ;
//修改数据库
ContentResolver contentResolver = getContentResolver ( ) ;
ContentValues contentValues = new ContentValues ( ) ;
final long id = mWorkingNote . getNoteId ( ) ;
contentValues . put ( "snippet" , mWorkingNote . mContent ) ;
contentResolver . update ( Uri . parse ( "content://micode_notes/note" ) , contentValues , "_id=?" , new String [ ] { "" + id } ) ;
ContentValues contentValues1 = new ContentValues ( ) ;
contentValues1 . put ( "content" , mWorkingNote . mContent ) ;
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 ;
}
}
public String getPath ( final Context context , final Uri uri ) {
final boolean isKitKat = Build . VERSION . SDK_INT > = Build . VERSION_CODES . KITKAT ;
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . KITKAT ) {
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 ) ;
}
}
// 文本
else if ( "content" . equalsIgnoreCase ( uri . getScheme ( ) ) ) {
return getDataColumn ( context , uri , null , null ) ;
}
// 文件
else if ( "file" . equalsIgnoreCase ( uri . getScheme ( ) ) ) {
return uri . getPath ( ) ;
}
}
return null ;
}
@Override
protected void onRestoreInstanceState ( Bundle savedInstanceState ) {
super . onRestoreInstanceState ( savedInstanceState ) ;
@ -263,14 +387,13 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
@Override
protected void onResume ( ) {
protected void onResume ( ) { //能获得用户焦点:可以操作
super . onResume ( ) ;
initNoteScreen ( ) ;
initNoteScreen ( ) ; //初始化便签屏幕
}
private void initNoteScreen ( ) {
mNoteEditor . setTextAppearance ( this , TextAppearanceResources
. getTexAppearanceResource ( mFontSizeId ) ) ;
mNoteEditor . setTextAppearance ( this , TextAppearanceResources . getTexAppearanceResource ( mFontSizeId ) ) ;
if ( mWorkingNote . getCheckListMode ( ) = = TextNote . MODE_CHECK_LIST ) {
switchToListMode ( mWorkingNote . getContent ( ) ) ;
} else {
@ -288,13 +411,54 @@ public class NoteEditActivity extends Activity implements OnClickListener,
| 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 ( ) ;
//将有图片路径的位置转换为图片
convertToImage ( ) ;
}
//路径字符串格式 转换为 图片image格式
private void convertToImage ( ) {
NoteEditText noteEditText = ( NoteEditText ) findViewById ( R . id . note_edit_view ) ; //获取当前的编辑框
Editable editable = noteEditText . getText ( ) ; //获取便签中的全部文本
String noteText = editable . toString ( ) ; //将获取的文本转换为字符串
int length = editable . length ( ) ; //内容的长度
// 获取文本路径(去掉最前面的[local]和最后面的[/local]
// 暴力搜索
for ( int i = 0 ; i < length ; i + + ) {
for ( int j = i ; j < length ; j + + ) {
String img_fragment = noteText . substring ( i , j + 1 ) ; //切割要检查的字符串
//[local]/storage/emulated/0/Pictures/IMG_20221202_015334.jpg[/local]
if ( img_fragment . length ( ) > 15 & & img_fragment . endsWith ( "[/local]" ) & & img_fragment . startsWith ( "[local]" ) ) {
int limit = 7 ; //[local]为7个字符
//[local][/local]共15个字符, 剩下的为真正的path长度
int len = img_fragment . length ( ) - 15 ;
//从[local]之后的len个字符就是path
String path = img_fragment . substring ( limit , limit + len ) ; //获取到了图片路径
Bitmap bitmap = null ; // 声明位图对象,获取图片路径所对应的图片
try {
bitmap = BitmapFactory . decodeFile ( path ) ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
if ( bitmap ! = null ) {
// 用ImageSpan实现图文并排的效果
ImageSpan imageSpan = new ImageSpan ( NoteEditActivity . this , bitmap ) ;
// 用SpannableString插入ImageSpan对象封装的图像
String ss = "[local]" + path + "[/local]" ;
SpannableString spannableString = new SpannableString ( ss ) ;
//5.将指定的标记对象附加到文本的开始...结束范围
spannableString . setSpan ( imageSpan , 0 , ss . length ( ) , Spannable . SPAN_EXCLUSIVE_EXCLUSIVE ) ;
Log . d ( TAG , "Create spannable string success!" ) ;
Editable edit_text = noteEditText . getEditableText ( ) ;
edit_text . delete ( i , i + len + 15 ) ; //删掉便签里面图片的路径文本
edit_text . insert ( i , spannableString ) ; //插入文本
}
}
}
}
}
private void showAlertHeader ( ) {
if ( mWorkingNote . hasClockAlert ( ) ) {
long time = System . currentTimeMillis ( ) ;
@ -358,8 +522,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
| | ev . getX ( ) > ( x + view . getWidth ( ) )
| | ev . getY ( ) < y
| | ev . getY ( ) > ( y + view . getHeight ( ) ) ) {
return false ;
}
return false ;
}
return true ;
}
@ -418,7 +582,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
intent . putExtra ( AppWidgetManager . EXTRA_APPWIDGET_IDS , new int [ ] {
mWorkingNote . getWidgetId ( )
mWorkingNote . getWidgetId ( )
} ) ;
sendBroadcast ( intent ) ;
@ -430,7 +594,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
if ( id = = R . id . btn_set_bg_color ) {
mNoteBgColorSelector . setVisibility ( View . VISIBLE ) ;
findViewById ( sBgSelectorSelectionMap . get ( mWorkingNote . getBgColorId ( ) ) ) . setVisibility (
- View . VISIBLE ) ;
View . VISIBLE ) ;
} else if ( sBgSelectorBtnsMap . containsKey ( id ) ) {
findViewById ( sBgSelectorSelectionMap . get ( mWorkingNote . getBgColorId ( ) ) ) . setVisibility (
View . GONE ) ;
@ -563,10 +727,6 @@ public class NoteEditActivity extends Activity implements OnClickListener,
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 ) ;
@ -773,12 +933,12 @@ public class NoteEditActivity extends Activity implements OnClickListener,
switchToListMode ( mNoteEditor . getText ( ) . toString ( ) ) ;
} else {
if ( ! getWorkingText ( ) ) {
mWorkingNote . setWorkingText ( mWorkingNote . getContent ( ) . replace ( TAG_UNCHECKED + " " ,
"" ) ) ;
mWorkingNote . setWorkingText ( mWorkingNote . getContent ( ) . replace ( TAG_UNCHECKED + " " , "" ) ) ;
}
mNoteEditor . setText ( getHighlightQueryResult ( mWorkingNote . getContent ( ) , mUserQuery ) ) ;
mEditTextList . setVisibility ( View . GONE ) ;
mNoteEditor . setVisibility ( View . VISIBLE ) ;
convertToImage ( ) ; //退出清单模式,应该将有图片的地方显示出来
}
}
@ -870,4 +1030,30 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private void showToast ( int resId , int duration ) {
Toast . makeText ( this , resId , duration ) . show ( ) ;
}
//获取数据列_获取此 Uri 的数据列的值。这对MediaStore Uris 和其他基于文件的 ContentProvider。
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 ;
}
//是否为媒体文件
public boolean isMediaDocument ( Uri uri ) {
return "com.android.providers.media.documents" . equals ( uri . getAuthority ( ) ) ;
}
}