@ -18,6 +18,17 @@ package net.micode.notes.ui;
import android.Manifest ;
import android.annotation.SuppressLint ;
import android.content.ContentResolver ;
import android.content.ContentValues ;
import android.database.Cursor ;
import android.graphics.Bitmap ;
import android.graphics.BitmapFactory ;
import android.net.Uri ;
import android.os.Build ;
import android.os.Environment ;
import android.provider.DocumentsContract ;
import android.provider.MediaStore ;
import android.speech.tts.TextToSpeech.OnInitListener ;
import android.app.AlarmManager ;
import android.app.AlertDialog ;
@ -42,6 +53,7 @@ import android.text.TextUtils;
import android.text.TextWatcher ;
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 ;
@ -74,6 +86,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.Locale ;
@ -163,6 +176,8 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen
private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10 ;
private static final int PHOTO_REQUEST = 1 ;
public static final String TAG_CHECKED = String . valueOf ( '\u221A' ) ;
public static final String TAG_UNCHECKED = String . valueOf ( '\u25A1' ) ;
@ -187,6 +202,24 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen
initResources ( ) ;
count ( ) ;
read ( ) ;
//根据id获取添加图片按钮
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 ) {
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 ) ;
}
} ) ;
}
/ * *
@ -311,6 +344,7 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen
mNoteEditor . setTextAppearance ( this , TextAppearanceResources
. getTexAppearanceResource ( mFontSizeId ) ) ;
//设置外观
if ( mWorkingNote . getCheckListMode ( ) = = TextNote . MODE_CHECK_LIST ) {
switchToListMode ( mWorkingNote . getContent ( ) ) ;
} else {
@ -332,6 +366,7 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen
* TODO : Add the menu for setting alert . Currently disable it because the DateTimePicker
* is not ready
* /
convertToImage ( ) ;
showAlertHeader ( ) ;
}
//设置闹钟的显示
@ -580,14 +615,6 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen
public boolean onOptionsItemSelected ( MenuItem item ) {
switch ( item . getItemId ( ) ) {
//根据菜单的id来编剧相关项目
case R . id . action_insert_image :
//绑定按钮的点击响应, 获取危险权限, 这里的100是申请码, 可以自己定义, 整数即可
ActivityCompat . requestPermissions ( NoteEditActivity . this , mPermissionList , 100 ) ;
//用于获取焦点,否则插入图片时没有响应
mNoteEditor . getFocusable ( ) ;
mNoteEditor . insertImage ( realPathFromUri , realPathFromUri + "\" style=\"max-width:100%" ) ;
break ;
case R . id . menu_new_note :
//创建一个新的便签
createNewNote ( ) ;
@ -1133,8 +1160,8 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen
int flag1 = - 1 ;
int flag2 = - 1 ;
do { //不计入表示图片的字符
flag1 = stringBuffer . indexOf ( " <img ") ;
flag2 = stringBuffer . indexOf ( " >") ;
flag1 = stringBuffer . indexOf ( " [local] ") ;
flag2 = stringBuffer . indexOf ( " [/local]") + 7 ;
if ( flag1 ! = - 1 & & flag2 ! = - 1 ) {
stringBuffer = stringBuffer . replace ( flag1 , flag2 + 1 , "" ) ;
}
@ -1189,7 +1216,7 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen
read . setOnClickListener ( new OnClickListener ( ) {
@Override
public void onClick ( View v ) {
mTTS . speak ( mNoteEditor. getText ( ) . toString ( ) , TextToSpeech . QUEUE_FLUSH , null ) ;
mTTS . speak ( TextChange( mNoteEditor. getText ( ) . toString ( ) ) , TextToSpeech . QUEUE_FLUSH , null ) ;
}
} ) ;
@ -1207,4 +1234,187 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen
// }
// });
//路径字符串格式 转换为 图片image格式
private void convertToImage ( ) {
net . micode . notes . ui . NoteEditText noteEditText = ( net . micode . notes . ui . 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
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个字符
//[local][/local]共15个字符, 剩下的为真正的path长度
int len = img_fragment . length ( ) - 15 ;
//从[local]之后的len个字符就是path
String path = img_fragment . substring ( limit , limit + len ) ; //获取到了图片路径
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 ) ;
//4.创建一个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 ) ; //6.删掉图片路径的文字
edit_text . insert ( i , spannableString ) ; //7.在路径的起始位置插入图片
}
}
}
}
}
//重写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 ( ) ; //1.获得图片的真实路径
Bitmap bitmap = null ;
try {
bitmap = BitmapFactory . decodeStream ( resolver . openInputStream ( originalUri ) ) ; //2.解码图片
} catch ( FileNotFoundException e ) {
Log . d ( TAG , "onActivityResult: get file_exception" ) ;
e . printStackTrace ( ) ;
}
if ( bitmap ! = null ) {
//3.根据Bitmap对象创建ImageSpan对象
Log . d ( TAG , "onActivityResult: bitmap is not null" ) ;
ImageSpan imageSpan = new ImageSpan ( NoteEditActivity . this , bitmap ) ;
String path = getPath ( this , originalUri ) ;
//4.使用[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 ) ;
//5.将选择的图片追加到EditText中光标所在位置
net . micode . notes . ui . NoteEditText e = ( net . micode . notes . ui . 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 ( ) ;
//6.把改动提交到数据库中,两个数据库表都要改的
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 ;
}
}
//获取文件的real path
@SuppressLint ( "NewApi" )
public static String getPath ( final Context context , final Uri uri ) {
if ( uri = = null ) {
return null ;
}
// 判斷是否為Android 4.4之後的版本
final boolean after44 = Build . VERSION . SDK_INT > = 19 ;
if ( after44 & & DocumentsContract . isDocumentUri ( context , uri ) ) {
// 如果是Android 4.4之後的版本, 而且屬於文件URI
final String authority = uri . getAuthority ( ) ;
// 判斷Authority是否為本地端檔案所使用的
if ( "com.android.externalstorage.documents" . equals ( authority ) ) {
// 外部儲存空間
final String docId = DocumentsContract . getDocumentId ( uri ) ;
final String [ ] divide = docId . split ( ":" ) ;
final String type = divide [ 0 ] ;
if ( "primary" . equals ( type ) ) {
String path = Environment . getExternalStorageDirectory ( ) . getAbsolutePath ( ) . concat ( "/" ) . concat ( divide [ 1 ] ) ;
return path ;
} else {
String path = "/storage/" . concat ( type ) . concat ( "/" ) . concat ( divide [ 1 ] ) ;
return path ;
}
} else if ( "com.android.providers.downloads.documents" . equals ( authority ) ) {
// 下載目錄
final String docId = DocumentsContract . getDocumentId ( uri ) ;
if ( docId . startsWith ( "raw:" ) ) {
final String path = docId . replaceFirst ( "raw:" , "" ) ;
return path ;
}
final Uri downloadUri = ContentUris . withAppendedId ( Uri . parse ( "content://downloads/public_downloads" ) , Long . parseLong ( docId ) ) ;
String path = queryAbsolutePath ( context , downloadUri ) ;
return path ;
} else if ( "com.android.providers.media.documents" . equals ( authority ) ) {
// 圖片、影音檔案
final String docId = DocumentsContract . getDocumentId ( uri ) ;
final String [ ] divide = docId . split ( ":" ) ;
final String type = divide [ 0 ] ;
Uri mediaUri = null ;
if ( "image" . equals ( type ) ) {
mediaUri = MediaStore . Images . Media . EXTERNAL_CONTENT_URI ;
} else if ( "video" . equals ( type ) ) {
mediaUri = MediaStore . Video . Media . EXTERNAL_CONTENT_URI ;
} else if ( "audio" . equals ( type ) ) {
mediaUri = MediaStore . Audio . Media . EXTERNAL_CONTENT_URI ;
} else {
return null ;
}
mediaUri = ContentUris . withAppendedId ( mediaUri , Long . parseLong ( divide [ 1 ] ) ) ;
String path = queryAbsolutePath ( context , mediaUri ) ;
return path ;
}
} else {
// 如果是一般的URI
final String scheme = uri . getScheme ( ) ;
String path = null ;
if ( "content" . equals ( scheme ) ) {
// 內容URI
path = queryAbsolutePath ( context , uri ) ;
} else if ( "file" . equals ( scheme ) ) {
// 檔案URI
path = uri . getPath ( ) ;
}
return path ;
}
return null ;
}
public static String queryAbsolutePath ( final Context context , final Uri uri ) {
final String [ ] projection = { MediaStore . MediaColumns . DATA } ;
Cursor cursor = null ;
try {
cursor = context . getContentResolver ( ) . query ( uri , projection , null , null , null ) ;
if ( cursor ! = null & & cursor . moveToFirst ( ) ) {
final int index = cursor . getColumnIndexOrThrow ( MediaStore . MediaColumns . DATA ) ;
return cursor . getString ( index ) ;
}
} catch ( final Exception ex ) {
ex . printStackTrace ( ) ;
if ( cursor ! = null ) {
cursor . close ( ) ;
}
}
return null ;
}
}