Adding example of querying for contact changes.
Bug: 8182147 Change-Id: I40a2b95b9e6ac0705b863e0e41f84654dfddaf5c
This commit is contained in:
@@ -1168,6 +1168,13 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".content.ChangedContacts" android:label="@string/activity_changed_contact">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.SAMPLE_CODE"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".content.InstallApk" android:label="@string/activity_install_apk"
|
||||
android:enabled="@bool/atLeastHoneycombMR2">
|
||||
<intent-filter>
|
||||
|
||||
@@ -450,6 +450,8 @@
|
||||
<string name="pick_phone">Pick a Phone</string>
|
||||
<string name="pick_address">Pick an Address</string>
|
||||
|
||||
<string name="activity_changed_contact">Content/Provider/Changed Contacts</string>
|
||||
|
||||
<string name="activity_install_apk">Content/Packages/Install Apk</string>
|
||||
|
||||
<!-- ============================== -->
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
package com.example.android.apis.content;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.LoaderManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.CursorLoader;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.Loader;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.database.CursorWrapper;
|
||||
import android.os.Bundle;
|
||||
import android.provider.ContactsContract;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.CursorAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* Demonstrates selecting contacts that have changed since a certain time.
|
||||
*/
|
||||
public class ChangedContacts extends Activity implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
private static final String CLASS = ChangedContacts.class.getSimpleName();
|
||||
|
||||
private static final String PREF_KEY_CHANGE = "timestamp_change";
|
||||
private static final String PREF_KEY_DELETE = "timestamp_delete";
|
||||
|
||||
private static final int ID_CHANGE_LOADER = 1;
|
||||
private static final int ID_DELETE_LOADER = 2;
|
||||
|
||||
/**
|
||||
* To see this in action, "clear data" for the contacts storage app in the system settings.
|
||||
* Then come into this app and hit any of the delta buttons. This will cause the contacts
|
||||
* database to be re-created.
|
||||
*/
|
||||
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Toast toast = Toast.makeText(context, "Contacts database created.", Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
}
|
||||
};
|
||||
|
||||
private DeleteAdapter mDeleteAdapter;
|
||||
private ChangeAdapter mChangeAdapter;
|
||||
private long mSearchTime;
|
||||
private TextView mDisplayView;
|
||||
private ListView mList;
|
||||
private Button mDeleteButton;
|
||||
private Button mChangeButton;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mDeleteAdapter = new DeleteAdapter(this, null, 0);
|
||||
mChangeAdapter = new ChangeAdapter(this, null, 0);
|
||||
|
||||
LinearLayout main = new LinearLayout(this);
|
||||
main.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
mChangeButton = new Button(this);
|
||||
mChangeButton.setText("Changed since " + getLastTimestamp(0, PREF_KEY_CHANGE));
|
||||
mChangeButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
changeClick();
|
||||
}
|
||||
});
|
||||
|
||||
mDeleteButton = new Button(this);
|
||||
mDeleteButton.setText("Deleted since " + getLastTimestamp(0, PREF_KEY_DELETE));
|
||||
mDeleteButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
deleteClick();
|
||||
}
|
||||
});
|
||||
|
||||
main.addView(mChangeButton);
|
||||
main.addView(mDeleteButton);
|
||||
|
||||
mDisplayView = new TextView(this);
|
||||
mDisplayView.setPadding(5, 5, 5, 5);
|
||||
main.addView(mDisplayView);
|
||||
|
||||
mList = new ListView(this);
|
||||
mList.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, 1f));
|
||||
main.addView(mList);
|
||||
|
||||
setContentView(main);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ContactsContract.Intents.CONTACTS_DATABASE_CREATED);
|
||||
registerReceiver(mReceiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
unregisterReceiver(mReceiver);
|
||||
}
|
||||
|
||||
private void changeClick() {
|
||||
mChangeAdapter.swapCursor(null);
|
||||
LoaderManager manager = getLoaderManager();
|
||||
manager.destroyLoader(ID_DELETE_LOADER);
|
||||
manager.restartLoader(ID_CHANGE_LOADER, null, this);
|
||||
}
|
||||
|
||||
private void deleteClick() {
|
||||
mChangeAdapter.swapCursor(null);
|
||||
LoaderManager manager = getLoaderManager();
|
||||
manager.destroyLoader(ID_CHANGE_LOADER);
|
||||
manager.restartLoader(ID_DELETE_LOADER, null, this);
|
||||
}
|
||||
|
||||
private void saveLastTimestamp(long time, String key) {
|
||||
SharedPreferences pref = getSharedPreferences(CLASS, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = pref.edit();
|
||||
editor.putLong(key, time);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
private long getLastTimestamp(long time, String key) {
|
||||
SharedPreferences pref = getSharedPreferences(CLASS, Context.MODE_PRIVATE);
|
||||
return pref.getLong(key, time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
switch(id) {
|
||||
case ID_CHANGE_LOADER:
|
||||
return getChangeLoader();
|
||||
case ID_DELETE_LOADER:
|
||||
return getDeleteLoader();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private CursorLoader getChangeLoader() {
|
||||
String[] projection = new String[]{
|
||||
ContactsContract.Data._ID,
|
||||
ContactsContract.Data.CONTACT_ID,
|
||||
ContactsContract.Data.DISPLAY_NAME,
|
||||
ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP
|
||||
};
|
||||
|
||||
mSearchTime = getLastTimestamp(0, PREF_KEY_CHANGE);
|
||||
|
||||
String selection = ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP + " > ?";
|
||||
String[] bindArgs = new String[]{mSearchTime + ""};
|
||||
return new CursorLoader(this, ContactsContract.Data.CONTENT_URI, projection,
|
||||
selection, bindArgs, ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP
|
||||
+ " desc, " + ContactsContract.Data.CONTACT_ID + " desc");
|
||||
}
|
||||
|
||||
private CursorLoader getDeleteLoader() {
|
||||
String[] projection = new String[]{
|
||||
ContactsContract.DeletedContacts.CONTACT_ID,
|
||||
ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP
|
||||
};
|
||||
|
||||
mSearchTime = getLastTimestamp(0, PREF_KEY_DELETE);
|
||||
|
||||
String selection = ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP + " > ?";
|
||||
String[] bindArgs = new String[]{mSearchTime + ""};
|
||||
return new CursorLoader(this, ContactsContract.DeletedContacts.CONTENT_URI, projection,
|
||||
selection, bindArgs, ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP +
|
||||
" desc");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor data) {
|
||||
long timestamp = 0;
|
||||
|
||||
|
||||
switch (cursorLoader.getId()) {
|
||||
case ID_CHANGE_LOADER:
|
||||
mDisplayView.setText(data.getCount() + " change(s) since " + mSearchTime);
|
||||
mList.setAdapter(mChangeAdapter);
|
||||
mChangeAdapter.swapCursor(data);
|
||||
|
||||
// Save the largest timestamp returned. Only need the first one due to the sort
|
||||
// order.
|
||||
if (data.moveToNext()) {
|
||||
timestamp = data.getLong(data.getColumnIndex(
|
||||
ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP));
|
||||
data.moveToPrevious();
|
||||
}
|
||||
if (timestamp > 0) {
|
||||
saveLastTimestamp(timestamp, PREF_KEY_CHANGE);
|
||||
mChangeButton.setText("Changed since " + timestamp);
|
||||
}
|
||||
break;
|
||||
case ID_DELETE_LOADER:
|
||||
mDisplayView.setText(data.getCount() + " delete(s) since " + mSearchTime);
|
||||
mList.setAdapter(mDeleteAdapter);
|
||||
mDeleteAdapter.swapCursor(new DeleteCursorWrapper(data));
|
||||
if (data.moveToNext()) {
|
||||
timestamp = data.getLong(data.getColumnIndex(
|
||||
ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP));
|
||||
data.moveToPrevious();
|
||||
}
|
||||
if (timestamp > 0) {
|
||||
saveLastTimestamp(timestamp, PREF_KEY_DELETE);
|
||||
mDeleteButton.setText("Deleted since " + timestamp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> cursorLoader) {
|
||||
mDisplayView.setText("");
|
||||
switch (cursorLoader.getId()) {
|
||||
case ID_CHANGE_LOADER:
|
||||
mChangeAdapter.swapCursor(null);
|
||||
break;
|
||||
case ID_DELETE_LOADER:
|
||||
mDeleteAdapter.swapCursor(null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private class DeleteCursorWrapper extends CursorWrapper {
|
||||
|
||||
/**
|
||||
* Creates a cursor wrapper.
|
||||
*
|
||||
* @param cursor The underlying cursor to wrap.
|
||||
*/
|
||||
public DeleteCursorWrapper(Cursor cursor) {
|
||||
super(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnIndexOrThrow(String columnName) {
|
||||
if (columnName.equals("_id")) {
|
||||
return super.getColumnIndex(ContactsContract.DeletedContacts.CONTACT_ID);
|
||||
}
|
||||
return super.getColumnIndex(columnName);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DeleteAdapter extends CursorAdapter {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
public DeleteAdapter(Context context, Cursor c, int flags) {
|
||||
super(context, c, flags);
|
||||
this.mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
LinearLayout item = new LinearLayout(mContext);
|
||||
item.addView(buildText(context));
|
||||
item.addView(buildText(context));
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
LinearLayout item = (LinearLayout) view;
|
||||
String id = cursor.getString(cursor.getColumnIndex(
|
||||
ContactsContract.DeletedContacts.CONTACT_ID));
|
||||
String timestamp = cursor.getString(cursor.getColumnIndex(
|
||||
ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP));
|
||||
|
||||
setText(item.getChildAt(0), id);
|
||||
setText(item.getChildAt(1), timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ChangeAdapter extends CursorAdapter {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
public ChangeAdapter(Context context, Cursor c, int flags) {
|
||||
super(context, c, flags);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
LinearLayout item = new LinearLayout(mContext);
|
||||
item.addView(buildText(context));
|
||||
item.addView(buildText(context));
|
||||
item.addView(buildText(context));
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
LinearLayout item = (LinearLayout) view;
|
||||
|
||||
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID));
|
||||
String name = cursor.getString(cursor.getColumnIndex(
|
||||
ContactsContract.Data.DISPLAY_NAME));
|
||||
String timestamp = cursor.getString(cursor.getColumnIndex(
|
||||
ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP));
|
||||
|
||||
setText(item.getChildAt(0), id);
|
||||
setText(item.getChildAt(1), name);
|
||||
setText(item.getChildAt(2), timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setText(View view, String value) {
|
||||
TextView text = (TextView) view;
|
||||
text.setText(value);
|
||||
}
|
||||
|
||||
private static TextView buildText(Context context) {
|
||||
TextView view = new TextView(context);
|
||||
view.setPadding(3, 3, 3, 3);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user