在手机中预置联系人/Service Number

本方案实现预置联系人(包含姓名、号码信息)至手机中;并保证该联系人是只读的,无法被删除/编辑。

代码分为两部分:

Part One 将预置的联系人插入到数据库中;

Part Two 保证预置联系人只读,无法被编辑删

(在三个地方屏蔽对预置联系人进行编辑处理:联系人详情界面、联系人多选界面、新建联系人选择合并联系人时)。

【注意】

如果您不需要限制预置联系人的删除/编辑操作,加入Part One部分代码即可,并去掉第一步importDefaultReadonlyContact() 中的语句:contactvalues.put(RawContacts.IS_SDN_CONTACT, -2);

Part One

1.新建PresetContactsImportProcessor.java

Before Android N:

Path: alps\packages\apps\Contacts\src\com\mediatek\contacts\simservice

package com.mediatek.contacts.simservice;

import com.mediatek.contacts.simservice.SIMProcessorManager.ProcessorCompleteListener;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.content.ContentProviderOperation;
import android.content.ContentValues;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email; //for usim
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.RawContacts;
import com.android.contacts.common.model.account.AccountType;
import android.os.RemoteException;
import java.util.ArrayList;
import com.mediatek.contacts.simservice.SIMProcessorManager.ProcessorCompleteListener;
import com.mediatek.contacts.simservice.SIMServiceUtils;
import com.mediatek.contacts.simservice.SIMServiceUtils.ServiceWorkData;
import com.mediatek.contacts.simcontact.SimCardUtils;
import com.mediatek.contacts.util.LogUtils;
import android.provider.ContactsContract.PhoneLookup;

public class PresetContactsImportProcessor extends SIMProcessorBase {
private static final String TAG = "PresetContactsImportProcessor";
private static boolean sIsRunningNumberCheck = false;
private static final int INSERT_PRESET_NUMBER_COUNT = xxx; //预置联系人的个数
private static final String INSERT_PRESET_NAME[] = {"xxx1","xxx2",...}; //各预置联系人的姓名
private static final String INSERT_PRESET_NUMBER[] = {"xxx1","xxx2",...}; //各预置联系人的号码

private int mSlotId;
private Context mContext;
public PresetContactsImportProcessor(Context context, int slotId, Intent intent, ProcessorCompleteListener listener) {
super(intent, listener);
mContext = context;
mSlotId = slotId;
}

@Override
public int getType() {
return SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS;
}

@Override
public void doWork() {
if (isCancelled()) {
LogUtils.d(TAG, "[doWork]cancel import preset contacts work. Thread id=" + Thread.currentThread().getId());
return;
}
importDefaultReadonlyContact();
}

private void importDefaultReadonlyContact(){
     Log.i(TAG, "isRunningNumberCheck before: " + sIsRunningNumberCheck);
     if (sIsRunningNumberCheck) {
        return;
     }
     sIsRunningNumberCheck = true;
     for(int i = 0;i < INSERT_PRESET_NUMBER_COUNT; i++) {
         Log.i(TAG, "isRunningNumberCheck after: " + sIsRunningNumberCheck);
         Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(INSERT_PRESET_NUMBER[i]));
         Log.i(TAG, "getContactInfoByPhoneNumbers(), uri = " + uri);
         Cursor contactCursor = mContext.getContentResolver().query(uri, 

new String[] {PhoneLookup.DISPLAY_NAME, PhoneLookup.PHOTO_ID}, null, null, null);
try {
if (contactCursor != null && contactCursor.getCount() > 0) {
return;
} else {
final ArrayList operationList = new ArrayList();
ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
ContentValues contactvalues = new ContentValues();
contactvalues.put(RawContacts.ACCOUNT_NAME, AccountType.ACCOUNT_NAME_LOCAL_PHONE);
contactvalues.put(RawContacts.ACCOUNT_TYPE, AccountType.ACCOUNT_TYPE_LOCAL_PHONE);
contactvalues.put(RawContacts.INDICATE_PHONE_SIM, ContactsContract.RawContacts.INDICATE_PHONE);
contactvalues.put(RawContacts.IS_SDN_CONTACT, -2);
builder.withValues(contactvalues);
builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
operationList.add(builder.build());
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
builder.withValue(Phone.TYPE, Phone.TYPE_MOBILE);
builder.withValue(Phone.NUMBER, INSERT_PRESET_NUMBER[i]);
builder.withValue(Data.IS_PRIMARY, 1);
operationList.add(builder.build());

              builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
              builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
              builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
              builder.withValue(StructuredName.DISPLAY_NAME, INSERT_PRESET_NAME[i]);
              operationList.add(builder.build());

              try {
                  mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
              } catch (RemoteException e) {
                  Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
              } catch (OperationApplicationException e) {
                  Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
              }
         }
     } finally {
         // when this service start,but the contactsprovider has not been started yet.
         // the contactCursor perhaps null, but not always.(first load will weekup the provider)
         // so add null block to avoid nullpointerexception
         if (contactCursor != null) {
              contactCursor.close();
         }
     } //END for
     Log.i(TAG, "isRunningNumberCheck insert: " + sIsRunningNumberCheck);
     sIsRunningNumberCheck = false;
  }
}

}
Android N:

Path: alps\packages\apps\Contacts\SimProcessor\src\com\mediatek\SimProcessor

package com.mediatek.simprocessor;

import android.content.Context;
import android.content.Intent;
import android.content.ContentProviderOperation;
import android.content.ContentValues;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.os.RemoteException;
import java.util.ArrayList;
import com.mediatek.simprocessor.SimProcessorManager.ProcessorCompleteListener;
import com.mediatek.simprocessor.SimServiceUtils;
import com.mediatek.simprocessor.Log;
import android.provider.ContactsContract.PhoneLookup;

public class PresetContactsImportProcessor extends SimProcessorBase {
private static final String TAG = "PresetContactsImportProcessor";
private static boolean sIsRunningNumberCheck = false;
private static final int INSERT_PRESET_NUMBER_COUNT = xxx; //预置联系人的个数
private static final String INSERT_PRESET_NAME[] = {"xxx1","xxx2", ...}; //各预置联系人的姓名
private static final String INSERT_PRESET_NUMBER[] = {"xxxx","xxxx", ...}; //各预置联系人的号码

private int mSubId;
private Context mContext;

public PresetContactsImportProcessor(Context context, int subId, Intent intent, ProcessorCompleteListener listener) {
    super(intent, listener);
    mContext = context;
    mSubId = subId;
}

@Override
public int getType() {
    return SimServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS;
}

@Override
public void doWork() {
    if (isCancelled()) {
        Log.d(TAG, "[doWork]cancel import preset contacts work. Thread id=" + Thread.currentThread().getId());
    return;
    }
    importDefaultReadonlyContact();
}

private void importDefaultReadonlyContact(){
    Log.i(TAG, "isRunningNumberCheck before: " + sIsRunningNumberCheck);
    if (sIsRunningNumberCheck) {
        return;
    }
    sIsRunningNumberCheck = true;
    for(int i = 0;i < INSERT_PRESET_NUMBER_COUNT; i++) {
        Log.i(TAG, "isRunningNumberCheck after: " + sIsRunningNumberCheck);
        Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(INSERT_PRESET_NUMBER[i]));
        Log.i(TAG, "getContactInfoByPhoneNumbers(), uri = " + uri);
        Cursor contactCursor = mContext.getContentResolver().query(uri, 
                new String[] {PhoneLookup.DISPLAY_NAME, PhoneLookup.PHOTO_ID}, null, null, null);
        try {
            if (contactCursor != null && contactCursor.getCount() > 0) {
                return;
            } else {
                final ArrayList operationList = new ArrayList();
                ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
                ContentValues contactvalues = new ContentValues();
                contactvalues.put(RawContacts.ACCOUNT_NAME, "Phone");
                contactvalues.put(RawContacts.ACCOUNT_TYPE, "Local Phone Account");
                contactvalues.put(RawContacts.INDICATE_PHONE_SIM, ContactsContract.RawContacts.INDICATE_PHONE);
                contactvalues.put(RawContacts.IS_SDN_CONTACT, -2);
                builder.withValues(contactvalues);
                builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
                operationList.add(builder.build());
                builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
                builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
                builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
                builder.withValue(Phone.TYPE, Phone.TYPE_MOBILE);
                builder.withValue(Phone.NUMBER, INSERT_PRESET_NUMBER[i]);
                builder.withValue(Data.IS_PRIMARY, 1);
                operationList.add(builder.build());

                builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
                builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
                builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
                builder.withValue(StructuredName.DISPLAY_NAME, INSERT_PRESET_NAME[i]);
                operationList.add(builder.build());

                try {
                    mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
                } catch (RemoteException e) {
                    Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
                } catch (OperationApplicationException e) {
                    Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
                }
            }
        } finally {
            // when this service start,but the contactsprovider has not been started yet.
            // the contactCursor perhaps null, but not always.(first load will weekup the provider)
            // so add null block to avoid nullpointerexception
            if (contactCursor != null) {
                contactCursor.close();
            }
        }
        Log.i(TAG, "isRunningNumberCheck insert: " + sIsRunningNumberCheck);
        sIsRunningNumberCheck = false;
    }
}

}

Before Android N:
修改SIMServiceUtils.java
Path: alps\packages\apps\ContactsCommon\src\com\mediatek\contacts\simservice

Android N:
修改SimServiceUtils.java
Path: alps\packages\apps\Contacts\SimProcessor\src\com\mediatek\SimProcessor

添加

public static final int SERVICE_WORK_IMPORT_PRESET_CONTACTS = 5;

Before Android N:
修改SIMProcessorManager.java
Path: alps\packages\apps\Contacts\src\com\mediatek\contacts\simservice
在createProcessor函数里添加

else if (workType == SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS) {
processor = new PresetContactsImportProcessor(context, subId, intent, listener);
}
Android N:
修改SimProcessorManager.java
Path: alps\packages\apps\Contacts\SimProcessor\src\com\mediatek\SimProcessor
在createProcessor函数里添加

else if (workType == SimServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS) {
processor = new PresetContactsImportProcessor(context, subId, intent, listener);
}

4.修改BootCmpReceiver.java

Before Android N:
Path: alps\packages\apps\Contacts\src\com\mediatek\contacts\simservice
添加如下方法:

/**

  • when boot complete,preset the service number directly.
    */
    private void presetServiceNumber(Context context) {
    Log.d(TAG, "presetServiceNumber");
    startSimService(context, -1, SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS);
    }
    Android N:
    Path: alps\packages\apps\Contacts\SimProcessor\src\com\mediatek\SimProcessor
    添加如下方法:

/**

  • when boot complete,preset the service number directly.
    */
    private void presetServiceNumber(Context context) {
    Log.d(TAG, "presetServiceNumber");
    startSimService(context, -1, SimServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS);
    }
  1. 修改BootCmpReceiver.java

Before Android N:
Path: alps\packages\apps\Contacts\src\com\mediatek\contacts\simservice
在onReceive()方法

public void onReceive(Context context, Intent intent) {
... ...
} else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
// fix ALPS01003520,when boot complete,remove the contacts if the
// card of a slot has been removed
if (!isPhbReady()) {
processBootComplete(context);
}
}
... ...
}
修改为:

public void onReceive(Context context, Intent intent) {
... ...
} else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
// fix ALPS01003520,when boot complete,remove the contacts if the
// card of a slot has been removed
if (!isPhbReady()) {
processBootComplete(context);
}

     // [START] add for Preset service number
     presetServiceNumber(context);
     // [END]
 }
 ... ...

}
Android N:

Path: alps\packages\apps\Contacts\SimProcessor\src\com\mediatek\SimProcessor

在onReceive()方法

public void onReceive(Context context, Intent intent) {
... ...
} else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
if (!isPhbReady()) {
processBootComplete(context);
} else {
processDupSimContacts(context);
}
}
... ...
}
修改为:

public void onReceive(Context context, Intent intent) {
... ...
} else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
if (!isPhbReady()) {
processBootComplete(context);
} else {
processDupSimContacts(context);
}

     // [START] add for Preset service number
     presetServiceNumber(context);
     // [END]
 }
 ... ...

}

Part Two

Before Android N:

File:DefaultContactListAdapter.java

Path: alps\packages\apps\ContactsCommon\src\com\android\contacts\common\list

Android N:

File:ContactsCommonListUtils.java

Path: alps\packages\apps\ContactsCommon\src\com\mediatek\contacts\util

configureOnlyShowPhoneContactsSelection函数中如下语句:

selection.append(Contacts.INDICATE_PHONE_SIM + "= ?");

selectionArgs.add("-1");
之后增加下面的代码

selection.append(" AND " + RawContacts.IS_SDN_CONTACT + " > -2");

  1. File:Contact.java

Path: alps\packages\apps\ContactsCommon\src\com\android\contacts\common\model

增加如下函数:

//add for Preset Contacts
public boolean isReadOnlyContact() {
return mIsSdnContact == -2;
}

Before Android N:

File:ContactLoaderFragment.java

Path:alps\packages\apps\contacts\src\com\android\contacts\detail

将isContactEditable函数修改为:

public boolean isContactEditable() {
// return mContactData != null && !mContactData.isDirectoryEntry() && !mContactData.isSdnContacts() && !mContactData.isInternationalDialNumber(); // before
return mContactData != null && !mContactData.isDirectoryEntry() && !mContactData.isSdnContacts() && !mContactData.isInternationalDialNumber() && !mContactData.isReadOnlyContact() ; // after
}
Android N:

File:QuickContactActivity.java

Path:alps\packages\apps\contacts\src\com\android\contacts\quickcontact

将isContactEditable函数修改为:

private boolean isContactEditable() {
// return mContactData != null && !mContactData.isDirectoryEntry() && !mContactData.isSdnContacts() ; // before
return mContactData != null && !mContactData.isDirectoryEntry() && !mContactData.isSdnContacts() && !mContactData.isReadOnlyContact() ; // after
}

File:ContactEntryListAdapter.java

Path:alps\packages\apps\contactscommon\src\com\android\contacts\common\list

在文件最后增加以下代码:

public boolean showReadOnlyContact = true;

public void setShowReadOnlyContact(boolean canDelete) {
showReadOnlyContact = canDelete;
}

File:ContactEntryListFragment.java

Path:alps\packages\apps\contactscommon\src\com\android\contacts\common\list

添加代码:

protected boolean isInstanceOfContactsMultiDeletionFragment(){
return false;
}
在onCreateLoader函数中,倒数第二句

mAdapter.configureLoader(loader, directoryId);
之前增加语句:

mAdapter.setShowReadOnlyContact(isInstanceOfContactsMultiDeletionFragment() ? false : true);
mAdapter.configureLoader(loader, directoryId);

Before Android M:

File: ContactsMultiDeletionFragment.java

Path:alps\packages\apps\Contacts\src\com\mediatek\contacts\list

添加代码:

protected boolean isInstanceOfContactsMultiDeletionFragment(){
return true;
}
[ Android M:

C File: packages/apps/ContactsCommon/src/com/android/contacts/common/list/ContactEntryListAdapter.java

public boolean isSdnNumber(int position) {
boolean isSdnNumber = false;
int partition = getPartitionForPosition(position);
if (partition >= 0) {
// Save the old cursor position - the call to getItem() may modify the cursor
// position.
int offset = getCursor(partition).getPosition();
Cursor cursor = (Cursor) getItem(position);
if (cursor != null) {
// [START]
// Before
// isSdnNumber = cursor.getInt(ContactQuery.IS_SDN_CONTACT) == 1;
// After
final long isSdn = cursor.getInt(ContactQuery.IS_SDN_CONTACT);
if (isSdn == 1 || isSdn == -2) {
isSdnNumber = true;
}
Log.d(TAG, "[isSdnNumber] isSdn = " + isSdn + ",isSdnNumber = " + isSdnNumber); //add log
// [END]

        // Restore the old cursor position.
        cursor.moveToPosition(offset);
    }
}
return isSdnNumber;

}
Android N:

C File: packages/apps/ContactsCommon/src/com/android/contacts/common/list/ContactEntryListAdapter.java

public boolean isSdnNumber(int position) {
boolean isSdnNumber = false;
int partition = getPartitionForPosition(position);
if (partition >= 0) {
// Save the old cursor position - the call to getItem() may modify the cursor
// position.
int offset = getCursor(partition).getPosition();
Cursor cursor = (Cursor) getItem(position);
if (cursor != null) {
// [START]
// Before
// isSdnNumber = cursor.getInt(cursor.getColumnIndex(Contacts.IS_SDN_CONTACT)) == 1;
// After
final long isSdn = cursor.getInt(cursor.getColumnIndex(Contacts.IS_SDN_CONTACT));
if (isSdn == 1 || isSdn == -2) {
isSdnNumber = true;
}
Log.d(TAG, "[isSdnNumber] isSdn = " + isSdn + ",isSdnNumber = " + isSdnNumber); //add log
// [END]

         // Restore the old cursor position.
         cursor.moveToPosition(offset);
     }
 }
 return isSdnNumber;

}

Before Android M:

File:MultiContactsBasePickerAdapter.java

Path:alps\packages\apps\contacts\src\com\mediatek\contacts\list

After Android M:

File:MultiBasePickerAdapter.java

Path:alps\packages\apps\contacts\src\com\mediatek\contacts\list

在configureSelection函数最后的语句

loader.setSelection(selection.toString());
之前增加语句:

if (!showReadOnlyContact ) {
selection.append(" AND " + Contacts.IS_SDN_CONTACT + "=0");
}

loader.setSelection(selection.toString());

8.File:AggregationSuggestionEngine.java

Path:alps\packages\apps\contacts\src\com\android\contacts\editor

在loadAggregationSuggestions函数
在语句:

sb.append(" AND " + Contacts.INDICATE_PHONE_SIM + "=-1");
之后添加:

sb.append(" AND " + Contacts.IS_SDN_CONTACT + "!=-2");

File:JoinContactListAdapter.java

Path:packages\apps\contacts\src\com\android\contacts\list
函数:public void configureLoader(CursorLoader cursorLoader, long directoryId)

Before Android N:

将:

loader.setSelection(Contacts._ID + "!=?"+" AND " + Contacts.INDICATE_PHONE_SIM + "=-1");
修改为:

loader.setSelection(Contacts._ID + "!=?"+" AND " + Contacts.INDICATE_PHONE_SIM + "=-1" + " AND " + Contacts.IS_SDN_CONTACT + "!=-2");
Android N:
将:

if (ContactsPortableUtils.MTK_PHONE_BOOK_SUPPORT) {
loader.setSelection(Contacts._ID + "!=?" + " AND " + Contacts.INDICATE_PHONE_SIM
+ "=-1");
} else {
loader.setSelection(Contacts._ID + "!=?");
}
修改为:

if (ContactsPortableUtils.MTK_PHONE_BOOK_SUPPORT) {
loader.setSelection(Contacts._ID + "!=?" + " AND " + Contacts.INDICATE_PHONE_SIM
+ "=-1" + " AND " + Contacts.IS_SDN_CONTACT + "!=-2");
} else {
loader.setSelection(Contacts._ID + "!=?" + " AND " + Contacts.IS_SDN_CONTACT + "!=-2");
}

Android N:
File: MultiSelectEntryContactListAdapter
Path: packages\apps\contacts\src\com\android\contacts\list
语句:

if (ContactsPortableUtils.MTK_PHONE_BOOK_SUPPORT
&& cursor.getInt(
cursor.getColumnIndex(ContactsContract.Contacts.IS_SDN_CONTACT)) == 1) {
view.setClickable(false);
view.hideCheckBox();
return;
}
修改为:

if ((ContactsPortableUtils.MTK_PHONE_BOOK_SUPPORT
&& cursor.getInt(cursor.getColumnIndex(
ContactsContract.Contacts.IS_SDN_CONTACT)) == 1)
|| cursor.getInt(cursor.getColumnIndex(
ContactsContract.Contacts.IS_SDN_CONTACT)) == -2) {
view.setClickable(false);
view.hideCheckBox();
return;
}
//End for Test

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,176评论 5 469
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,190评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,232评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,953评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,879评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,177评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,626评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,295评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,436评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,365评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,414评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,096评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,685评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,771评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,987评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,438评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,032评论 2 341

推荐阅读更多精彩内容