分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow
在Android 4.0中,google已经把移除常用联系人这个功能去掉。
当用户在进行拨打电话,接听电话等电话行为时,系统会自动对其对应号码的使用进行计数。然后根据计数情况来显示常用联系人。 移除常用联系人只是指把该联系人从常用联系人列表移除。
移除常用联系人基本思想是:
在数据库中,保留goolge原来中用对通话进行计数的字段
DataUsageStatColumns.TIMES_USED
,新增加一个字段
DataUsageStatColumns.FAKE_TIMES_USED
来对通话进行计数,并提供一些对该字段操作接口,然后根据我们
DataUsageStatColumns.FAKE_TIMES_USED
计数情况来显示常用联系人
移除常用联系该功能的实现主要分为两个部分:
第一,
当用户从Call log删除一个通话记录,表明用户不想和该联系人的该通话记录本看到,因此应该把该联系人从常用联系人列表中移除。
第二,
用户可以从常用联系人列表中移除一个联系人,同时把和该联系人相关的Call log记录都删除掉。
添加移除常用联系功能,需要修改两个应用程序的源码,一个是com.android.providers.contacts,另一个是com.android.contacts
。在MTK6575平台上,对于应用
com.android.providers.contacts改动的文件有
packages
/
providers
/
ContactsProvider
/
src
/
com
/
android
/
providers
/
contacts
/
CallLogProvider
.
java
packages
/
providers
/
ContactsProvider
/
src
/
com
/
android
/
providers
/
contacts
/
ContactsProvider2
.
java
packages
/
providers
/
ContactsProvider
/
src
/
com
/
android
/
providers
/
contacts
/
ContactsDatabaseHelper
.
java
主要修改如下:
文件packages/providers/ContactsProvider/src/com/android/providers/contacts/CallLogProvider.java
@@
-
127
,
7
+
132
,
22
@@
public
class
CallLogProvider
extends
ContentProvider
{
sCallsProjectionMap
.
put
(
Calls
.
DATA_ID
,
Calls
.
DATA_ID
);
/* The previous lines are provided and maintained by Mediatek inc.*/
}
+
private
static
final
HashMap
<
String
,
String
>
sCallsToJoin_USAGE_STAT_ProjectionMap
;
+
static
{
+
/*Calls projection map*/
+
sCallsToJoin_USAGE_STAT_ProjectionMap
=
new
HashMap
<
String
,
String
>();
+
sCallsToJoin_USAGE_STAT_ProjectionMap
.
put
(
Calls
.
_ID
,
Tables
.
CALLS
+
"._id as "
+
Calls
.
_ID
);
+
sCallsToJoin_USAGE_STAT_ProjectionMap
.
put
(
Calls
.
NUMBER
,
Calls
.
NUMBER
);
+
sCallsToJoin_USAGE_STAT_ProjectionMap
.
put
(
Calls
.
DATE
,
Calls
.
DATE
);
+
sCallsToJoin_USAGE_STAT_ProjectionMap
.
put
(
Calls
.
DURATION
,
Calls
.
DURATION
);
+
sCallsToJoin_USAGE_STAT_ProjectionMap
.
put
(
Calls
.
TYPE
,
Calls
.
TYPE
);
+
/* The fillowing lines are provided and maintained by Mediatek inc.*/
+
sCallsToJoin_USAGE_STAT_ProjectionMap
.
put
(
Calls
.
SIM_ID
,
Calls
.
SIM_ID
);
+
sCallsToJoin_USAGE_STAT_ProjectionMap
.
put
(
Calls
.
RAW_CONTACT_ID
,
Calls
.
RAW_CONTACT_ID
);
+
sCallsToJoin_USAGE_STAT_ProjectionMap
.
put
(
Calls
.
DATA_ID
,
Calls
.
DATA_ID
);
+
/* The previous lines are provided and maintained by Mediatek inc.*/
+
}
private
static
final
String
mstableCallsJoinData
=
Tables
.
CALLS
+
" LEFT JOIN "
+
" (SELECT * FROM "
+
Views
.
DATA
+
" WHERE "
+
Data
.
_ID
+
" IN "
+
"(SELECT "
+
Calls
.
DATA_ID
+
" FROM "
+
Tables
.
CALLS
+
")) AS "
+
Views
.
DATA
@@
-
605
,
7
+
625
,
7
@@
public
class
CallLogProvider
extends
ContentProvider
{
return
getDatabaseModifier
(
db
).
update
(
Tables
.
CALLS
,
values
,
selectionBuilder
.
build
(),
selectionArgs
);
}
-
+
IContentProvider
mContentProvider
;
@Override
public
int
delete
(
Uri
uri
,
String
selection
,
String
[]
selectionArgs
)
{
SelectionBuilder
selectionBuilder
=
new
SelectionBuilder
(
selection
);
@@
-
640
,
7
+
660
,
31
@@
public
class
CallLogProvider
extends
ContentProvider
{
*
selectionBuilder
.
build
(),
selectionArgs
);
*
/
case CALLS: {
- int count = 0;
+ ArrayList<Long> idList=new ArrayList<Long> ();
+ ArrayList<Integer> typeList=new ArrayList<Integer> ();
+
+ Cursor c = db.query(true,
+ Tables.CALLS, new String[] { Calls._ID, Calls.DATA_ID,Calls.TYPE},
+ selection, selectionArgs,null,null,null,null);
+ long id=-1;
+ if(c.moveToFirst())
+ {
+ do
+ {
+ id=c.getLong(1);
+ if(id>0)
+ {
+ idList.add(id);
+ typeList.add(c.getInt(2));
+ }
+
+ }while(c.moveToNext());
+ }
+ long ids[]=new long[idList.size()];
+ for(int i=0;i<ids.length;i++)
+ ids[i]=idList.get(i);
+ c.close();
+ int count = 0;
if (FeatureOption.MTK_SEARCH_DB_SUPPORT == true) {
/
*
*
update name_lookup
for
usage of dialer search
:
@@
-
788
,
6
+
832
,
36
@@
public
class
CallLogProvider
extends
ContentProvider
{
if
(
count
>
0
)
{
notifyDialerSearchChange
();
}
+
if
(
ids
.
length
>
0
&&
uri
.
getBooleanQueryParameter
(
"updateFakeTimesUsed"
,
true
))
+
{
+
IContentProvider
cp
=
null
;
+
synchronized
(
this
)
{
+
cp
=
mContentProvider
;
+
if
(
cp
==
null
)
{
+
cp
=
mContentProvider
=
getContext
().
getContentResolver
().
acquireProvider
(
ContactsContract
.
AUTHORITY
);
+
}
+
}
+
try
{
+
Bundle
bundle
=
new
Bundle
();
+
bundle
.
putLongArray
(
"dataIds"
,
ids
);
+
//bundle.putIntArray("types", types);
+ //bundle.putIntArray("counts", counts);
+ Bundle b = cp.call(ContactsProvider2.CALL_METHOD_UPDATE_FAKE_TIMES_USED, "Asynchronous", bundle);
+ /*if (b != null) {
+ int v = b.getInt("count",0);
+ if(v!=count)
+ {
+ Log.e(TAG, "some erro happpend in CALL_METHOD_UPDATE_FAKE_TIMES_USED");
+ }
+ }*/
+ // If the response Bundle is null, we fall through
+ // to the query interface below.
+ } catch (RemoteException e) {
+ Log.w(TAG, "", e);
+ // Not supported by the remote side? Fall through
+ // to query().
+ }
+ }
return count;
}
文件packages/providers/ContactsProvider/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@
-
733
,
7
+
733
,
12
@@
import
com
.
mediatek
.
providers
.
contacts
.
ContactsFeatureConstants
.
FeatureOption
;
public
static
final
String
TIMES_USED
=
"times_used"
;
public
static
final
String
CONCRETE_TIMES_USED
=
Tables
.
DATA_USAGE_STAT
+
"."
+
TIMES_USED
;
-
+
/** type: INTEGER */
+
public
static
final
String
FAKE_TIMES_USED
=
"fake_times_used"
;
+
public
static
final
String
CONCRETE_FAKE_TIMES_USED
=
+
Tables
.
DATA_USAGE_STAT
+
"."
+
FAKE_TIMES_USED
;
+
/*add by Robin Hu*/
/** type: INTEGER */
public
static
final
String
USAGE_TYPE_INT
=
"usage_type"
;
public
static
final
String
CONCRETE_USAGE_TYPE
=
@@
-
1383
,
6
+
1388
,
7
@@
import
com
.
mediatek
.
providers
.
contacts
.
ContactsFeatureConstants
.
FeatureOption
;
DataUsageStatColumns
.
DATA_ID
+
" INTEGER NOT NULL, "
+
DataUsageStatColumns
.
USAGE_TYPE_INT
+
" INTEGER NOT NULL DEFAULT 0, "
+
DataUsageStatColumns
.
TIMES_USED
+
" INTEGER NOT NULL DEFAULT 0, "
+
+
DataUsageStatColumns
.
FAKE_TIMES_USED
+
" INTEGER NOT NULL DEFAULT 0, "
+
DataUsageStatColumns
.
LAST_TIME_USED
+
" INTERGER NOT NULL DEFAULT 0, "
+
"FOREIGN KEY("
+
DataUsageStatColumns
.
DATA_ID
+
") REFERENCES "
+
Tables
.
DATA
+
"("
+
Data
.
_ID
+
")"
+
@@
-
1918
,
6
+
1924
,
7
@@
import
com
.
mediatek
.
providers
.
contacts
.
ContactsFeatureConstants
.
FeatureOption
;
+
MimetypesColumns
.
CONCRETE_MIMETYPE
+
" AS "
+
Data
.
MIMETYPE
+
", "
+
DataUsageStatColumns
.
USAGE_TYPE_INT
+
", "
+
DataUsageStatColumns
.
TIMES_USED
+
", "
+
+
DataUsageStatColumns
.
FAKE_TIMES_USED
+
", "
+
DataUsageStatColumns
.
LAST_TIME_USED
+
" FROM "
+
Tables
.
DATA_USAGE_STAT
+
" JOIN "
+
Tables
.
DATA
+
" ON ("
文件packages/providers/ContactsProvider/src/com/android/providers/contacts/ContactsProvider2.java
@@
-
261
,
8
+
264
,
7
@@
public
class
ContactsProvider2
extends
AbstractContactsProvider
*
the total times contacted
.
See
also
{
@link
#sStrequentFrequentProjectionMap}.
*/
private static final String TIMES_USED_SORT_COLUMN = "times_used_sort";
-
- private static final String FREQUENT_ORDER_BY = DataUsageStatColumns.TIMES_USED + " DESC,"
+ private static final String FREQUENT_ORDER_BY = DataUsageStatColumns.FAKE_TIMES_USED + " DESC,"
+ Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
/* package */ static final String UPDATE_TIMES_CONTACTED_CONTACTS_TABLE =
@@ -745,7 +747,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
private static final ProjectionMap sStrequentFrequentProjectionMap = ProjectionMap.builder()
.addAll(sContactsProjectionMap)
- .add(TIMES_USED_SORT_COLUMN, "SUM(" + DataUsageStatColumns.CONCRETE_TIMES_USED + ")")
+ .add(TIMES_USED_SORT_COLUMN, "SUM(" + DataUsageStatColumns.CONCRETE_FAKE_TIMES_USED + ")")
.build();
/**
@@ -771,7 +773,8 @@ public class ContactsProvider2 extends AbstractContactsProvider
private static final ProjectionMap sStrequentPhoneOnlyFrequentProjectionMap
= ProjectionMap.builder()
.addAll(sContactsProjectionMap)
- .add(TIMES_USED_SORT_COLUMN, DataUsageStatColumns.CONCRETE_TIMES_USED)
+ //.add(TIMES_USED_SORT_COLUMN, DataUsageStatColumns.CONCRETE_TIMES_USED)
+ .add(TIMES_USED_SORT_COLUMN, DataUsageStatColumns.CONCRETE_FAKE_TIMES_USED)
.add(Phone.NUMBER)
.add(Phone.TYPE)
.add(Phone.LABEL)
@@ -2218,7 +2221,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- if (mWriteAccessLatch != null) {
+ if (mWriteAccessLatch != null) {
// We are stuck trying to upgrade contacts db. The only update request
// allowed in this case is an update of provider status, which will trigger
// an attempt to upgrade contacts again.
@@ -2295,7 +2298,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
/* package */ void substituteDb(SQLiteDatabase db) {
mActiveDb.set(db);
}
-
+Handler handler=new Handler();
@Override
public Bundle call(String method, String arg, Bundle extras) {
waitForAccess(mReadAccessLatch);
@@ -2315,6 +2318,72 @@ public class ContactsProvider2 extends AbstractContactsProvider
response.putParcelable(Authorization.KEY_AUTHORIZED_URI, authUri);
return response;
}
+ else if (CALL_METHOD_UPDATE_FAKE_TIMES_USED.equals(method)) {
+ String strUri=extras.getString("Uri");
+ if(strUri==null)
+ {
+ final long[] dataIds= extras.getLongArray("dataIds");
+ //final int[] types=extras.getIntArray("types");
+ //final int [] counts=extras.getIntArray("counts");
+ if("Asynchronous".equals(arg))
+ {
+ Runnable r=new Runnable()
+ {
+
+ @Override
+ public void run() {
+ // TODO Auto-generated method stub
+ for(int i=0;i<dataIds.length;i++)
+ update_FAKE_TIMES_USED_Stat(dataIds[i],ID_TYPE_VIEW_DATA,false);
+ }};
+ handler.postDelayed(r, 10);
+ return null;
+ }
+ else
+ {
+ int count=0;
+ for(int i=0;i<dataIds.length;i++)
+ count+= update_FAKE_TIMES_USED_Stat(dataIds[i],ID_TYPE_VIEW_DATA,false);
+ Bundle response = new Bundle();
+ response.putInt("count", count);
+ return response;
+ }
+ }
+ else
+ {
+ Uri uri=Uri.parse(strUri);
+ int match = sUriMatcher.match(uri);
+ match = processMatchEx(match, uri);
+ int count=-1;
+ List<String> pathSegments = uri.getPathSegments();
+ if(match==CONTACTS_LOOKUP_ID)
+ {
+ int type=ID_TYPE_VIEW_DATA;
+ if(arg!=null)
+ {
+ if(arg.equals("ID_TYPE_CONTACT"))
+ type=ID_TYPE_CONTACT;
+ else if(arg.equals("ID_TYPE_RAW_CONTACT"))
+ {
+ type=ID_TYPE_RAW_CONTACT;
+ }
+ }
+ long id = Long.parseLong(pathSegments.get(3));
+ count= update_FAKE_TIMES_USED_Stat(id,type,true);
+ }
+ /*else if(match==CONTACTS_LOOKUP)
+ {
+ String contactLookupKey = pathSegments.get(2);
+ count= update_FAKE_TIMES_USED_Stat(contactLookupKey);
+ }*/
+ if(count!=-1)
+ {
+ Bundle response = new Bundle();
+ response.putInt("count", count);
+ return response;
+ }
+ }
+ }
return null;
}
@@ -5515,7 +5584,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
// UNION ALL
// (SQL for listing frequently contacted items)
// ORDER BY ...
-
+
final boolean phoneOnly = readBooleanQueryParameter(
uri, ContactsContract.STREQUENT_PHONE_ONLY, false);
if (match == CONTACTS_STREQUENT_FILTER && uri.getPathSegments().size() > 3) {
@@ -5569,7 +5638,8 @@ public class ContactsProvider2 extends AbstractContactsProvider
+ " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "="
+ DataColumns.CONCRETE_ID + " AND "
+ DataUsageStatColumns.CONCRETE_USAGE_TYPE + "="
- + DataUsageStatColumns.USAGE_TYPE_INT_CALL + ")");
+ + DataUsageStatColumns.USAGE_TYPE_INT_CALL
+ + " AND "+DataUsageStatColumns.CONCRETE_FAKE_TIMES_USED+">0"+")");
appendContactPresenceJoin(tableBuilder, projection, RawContacts.CONTACT_ID);
appendContactStatusUpdateJoin(tableBuilder, projection,
ContactsColumns.LAST_STATUS_UPDATE_ID);
@@ -6955,7 +7025,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
if (includeDataUsageStat) {
sb.append(" ON (" +
DbQueryUtils.concatenateClauses(
- DataUsageStatColumns.CONCRETE_TIMES_USED + " > 0",
+ DataUsageStatColumns.CONCRETE_FAKE_TIMES_USED + " > 0",
RawContacts.CONTACT_ID + "=" + Views.CONTACTS + "." + Contacts._ID) +
")");
}
@@ -8431,7 +8501,6 @@ public class ContactsProvider2 extends AbstractContactsProvider
return successful;
}
-
/**
* Update {@link Tables#DATA_USAGE_STAT}.
*
@@ -8444,7 +8513,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
final String where = DataUsageStatColumns.DATA_ID + " =? AND "
+ DataUsageStatColumns.USAGE_TYPE_INT + " =?";
final String[] columns =
- new String[] { DataUsageStatColumns._ID, DataUsageStatColumns.TIMES_USED };
+ new String[] { DataUsageStatColumns._ID, DataUsageStatColumns.TIMES_USED, DataUsageStatColumns.FAKE_TIMES_USED };
final ContentValues values = new ContentValues();
for (Long dataId : dataIds) {
final String[] args = new String[] { dataId.toString(), String.valueOf(typeInt) };
@@ -8460,6 +8529,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
} else {
values.clear();
values.put(DataUsageStatColumns.TIMES_USED, cursor.getInt(1) + 1);
+ values.put(DataUsageStatColumns.FAKE_TIMES_USED, cursor.getInt(2) + 1);
values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis);
mActiveDb.get().update(Tables.DATA_USAGE_STAT, values,
DataUsageStatColumns._ID + " =?",
@@ -8470,6 +8540,7 @@ public class ContactsProvider2 extends AbstractContactsProvider
values.put(DataUsageStatColumns.DATA_ID, dataId);
values.put(DataUsageStatColumns.USAGE_TYPE_INT, typeInt);
values.put(DataUsageStatColumns.TIMES_USED, 1);
+ values.put(DataUsageStatColumns.FAKE_TIMES_USED, 1);
values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis);
mActiveDb.get().insert(Tables.DATA_USAGE_STAT, null, values);
}
@@ -8484,7 +8555,213 @@ public class ContactsProvider2 extends AbstractContactsProvider
return dataIds.size();
}
+ /**
+ * Update {@link Tables#DATA_USAGE_STAT}.
+ *
+ * @return the number of rows affected.
+ */
+ final int update_FAKE_TIMES_USED_Stat(
+ long dataIds[])
+ {
+ return update_FAKE_TIMES_USED_Stat(dataIds,null,null);
+ }
+ /* package */ int update_FAKE_TIMES_USED_Stat(
+ long dataIds[], int types[], int counts[]) {
+ //int typeInt;
+ /*final String where = DataUsageStatColumns.DATA_ID + " =? AND "
+ + DataUsageStatColumns.USAGE_TYPE_INT + " ="+DataUsageStatColumns.USAGE_TYPE_INT_CALL;*/
+ final String where = DataUsageStatColumns.DATA_ID + " =?";
+
+ final String[] columns =
+ new String[] { DataUsageStatColumns._ID, DataUsageStatColumns.FAKE_TIMES_USED };
+ final ContentValues values = new ContentValues();
+ int n=0;
+ int i=0;
+ long dataId=0;
+ if(mActiveDb.get()==null)
+ mActiveDb.set(mContactsHelper.getWritableDatabase());
+ for (i=0; i<dataIds.length;i++) {
+ dataId=dataIds[i];
+ //typeInt = types[i];
+ //typeInt = sDataUsageTypeMap.get(types[i]);
+ final String[] args = new String[] { dataId+""};
+ mActiveDb.get().beginTransaction();
+ try {
+ final Cursor cursor = mActiveDb.get().query(Tables.DATA_USAGE_STAT, columns, where,
+ args, null, null, null);
+ try {
+ if (cursor.getCount() > 0) {
+ if (!cursor.moveToFirst()) {
+ Log.e(TAG,
+ "moveToFirst() failed while getAccount() returned non-zero.");
+ } else {
+
+ //n=cursor.getInt(1) + counts[i];
+ n=0;//force clear
+ do{
+ values.clear();
+ values.put(DataUsageStatColumns.FAKE_TIMES_USED,n);
+ mActiveDb.get().update(Tables.DATA_USAGE_STAT, values,
+ DataUsageStatColumns._ID + " =?",
+ new String[] { cursor.getString(0) });
+ }while(cursor.moveToNext());
+ }
+ } else {
+ Log.wtf(TAG, "warning!There is no record for dataId=="+dataId+" and Type=="+DataUsageStatColumns.USAGE_TYPE_INT_CALL);