Can I extend Androids Contacts database? - android

I was wondering is it possible to extend the Android Contacts database?
From here - http://d.android.com/reference/android/provider/ContactsContract.html
It says:
ContactsContract defines an extensible
database of contact-related
information
Extensible would suggest to me that I can add in more data to the contacts application outside the normal values such as Name, number, email, work number, home number etc..
However the examples of this page - http://d.android.com/reference/android/provider/ContactsContract.RawContacts.html only show how to insert the standard values like name and not how to add a new field to a contact.
Furthermore a search on the web does not turn up much information on extending the contacts data.
So I was wondering is it even possible or does the extensible refer to some other part of the contacts?
For example I would like to add in an additional field for contacts that have special privileges within my app so when a user looks at the contacts he or she knows what users they can use my app with.
Is this possible?

You can store custom data in the contacts database. However "when a user looks at the contacts he or she knows what users they can use my app with," may not be possible if you are thinking users will be able to see the custom data you inserted while using the built-in Android Contacts application. You would have to display the custom data in your own application.
The javadocs for the ContactsContract.Data class should provide an explanation, as well as the Contacts article.
To use this you'll need to get a raw contact id by querying the RawContacts.
Here some example code that might help you get started...
private void makePowerful(int rawContactId) {
ContentValues values = new ContentValues();
values.put(Privilege.RAW_CONTACT_ID, rawContactId);
values.put(Privilege.MIMETYPE, Privilege.CONTENT_ITEM_TYPE);
values.put(Privilege.PRIVILEGE_LEVEL, Privilege.TYPE_POWERFUL);
Uri uri = getContentResolver().insert(Data.CONTENT_URI, values);
}
public static final class Privilege implements ContactsContract.DataColumnsWithJoins, ContactsContract.CommonDataKinds.CommonColumns {
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/my_app_privilege";
public static final int TYPE_POWERFUL = 1;
public static final int TYPE_WEAK = 2;
public static final String PRIVILEGE_LEVEL = DATA1;
private Privilege() { }
}

Related

DC2type on greenDao

I am using GreenDao for Android application, with some specification, for example, I have a Contact Model with some information like name, avatar, phone number, etc...
Right now the need is to change from only one phone number to a multiphone number.
Instead of creating two tables (table for numbers, and table for contacts), I really need just one information is the number so in my backend the contact numbers is stocked on a DC2type, (a json array saved as a string).
Do we have a possibility to do that using GreenDao?
i search for a solution or a DC2type implementation , etc ... and nothing is found
so i decide to created by my self , and this is what i did :
using the #Convert annotation presented of GreenDao 3 :
#Property(nameInDb = "phoneNumbers")
#Convert(converter = PhoneNumbersConverter.class, columnType = String.class)
private List<String> phoneNumbers;
static class PhoneNumbersConverter implements PropertyConverter<List<String>, String> {
#Override
public List<String> convertToEntityProperty(String databaseValue) {
List<String> listOfStrings = new Gson().fromJson(databaseValue,List.class);
return listOfStrings;
}
#Override
public String convertToDatabaseValue(List<String> entityProperty) {
String json = new Gson().toJson(entityProperty);
return json;
}
}
short story long , i create a json to array parser
thanks to myself to helped me :D

Android: performance cost of content provider queries within queries

Writing this on the fly, so I apologize for the code sample. This is NOT real code, it's something I wrote in a plain text editor on the fly. No compile checking, couldn't remember all the exact class and method names, etc. It's just a written concept of what I'm trying to do, I'm looking for feedback on the broader concepts.
I'm working on retrieving a list of contacts from the content provider. I want to be able to filter the results based on the contact's account name. the user will be presented with all available accounts, and will select which ones are to be used, and then that will be used in the retrieval method.
The thing is, the account name is in RawContacts, and the rest of the info I want (display name, lookupID) is in Contacts. I know that ContactsContract.Contacts.Entity is the shortcut to access all of this, so this code sample is what I'm planning to do.
Again, this is written on the fly with no IDE or looking up methods or anything. I'm sure my syntax is bad in many places, but this shows the concept I'm trying to do.
private static final URI URI = ContactsContract.Contacts.URI;
private static final String[] FIRST_PROJECTION = new String[]{
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.LOOKUP_KEY
};
private String[] acceptedAccountNames = {Accepted Account Names Will Go Here (dynamic)};
private static final String[] SECOND_PROJECTION = new String[]{
ContactsContract.Contacts.Entity.ACCOUNT_NAME //This is whatever the entity -> RawContacts field name would be
};
public List<Contact> loadContacts(Context context){
List<Contact> contacts = new ArrayList<>();
ContentProvider provider = context.getContentProvider();
Cursor contactsCursor = provider.query(URI, FIRST_PROJECTION, null, null);
contactsCursor.movetoFirst();
while(!contactsCursor.isAtLast()){
String name = contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
long lookupKey = contactsCursor.getLong(contactsCursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
Uri idUri = Uri.makeWithId(URI, lookupKey);
Uri entityUri = Uri.makeWithTableName(idUri, "entity");
Cursor contactEntityCursor = provider.query(entityUri, SECOND_PROJECTION, null, null);
contactEntityCursor.moveToFirst();
String accountName = contactEntityCursor.getString(contactEntityCursor.getColumnIndex(ContactsContract.Contacts.Entity.ACCOUNT_NAME));
if(Arrays.asList(acceptedAccountNames).contains(accountName)){
Contact contact = new Contact(lookupKey, name);
contacts.add(contact);
}
contactsCursor.moveToNext();
}
return contacts;
}
As you can see, I create a cursor while looping over another cursor. I'm essentially creating a new cursor for each contact in the list.
My question is twofold:
1) What would be the performance implications of this? With a large enough list, would this severely hurt app performance?
2) Is there a better way to do this? As in, a way to do this in a single query, getting all the data I'm looking for in the cursor.
Thanks so much in advance.

How to load database data, and store it into array list, and show it into ListVIew

So, I want to build an app to view some data from database. I already have the database, also already made some entities that have exactly same properties name with the column names in database. And also I put the database into database directory by copying from assets folder.
What I want to achieve is, I want to pull some data, and put it into array list, so I can show it in ListView in fragment.
Is there any convenient way to pull some data without querying (like loadAll() function) ?
For now, I'm using cursor to save the pulled data using query, and assign its properties one by one using set function like setName(String name).
After that, I show the list using CursorAdapter.
It would be like this
public class FrameCursor extends CursorWrapper{
/**
* Creates a cursor wrapper.
*
* #param cursor The underlying cursor to wrap.
*/
public FrameCursor(Cursor cursor) {
super(cursor);
}
public ZFrame getFrame(){
if(isBeforeFirst() || isAfterLast()){
return null;
}
ZFrame frame = new ZFrame();
ZFrameDao frameDao = new ZFrameDao();
int frameEdition = getInt(getColumnIndex(COLUMN_FRAME_EDITION));
int frameId = getInt(getColumnIndex(COLUMN_FRAME_ID));
int frameNumber = getInt(getColumnIndex(COLUMN_FRAME_NUMBER));
int frameType = getInt(getColumnIndex(COLUMN_FRAME_TYPE));
int frameBookmark = getInt(getColumnIndex(COLUMN_FRAME_BOOKMARK));
int frameGlyph = getInt(getColumnIndex(COLUMN_FRAME_GLYPH));
int frameLesson = getInt(getColumnIndex(COLUMN_FRAME_LESSON));
String frameAllReading = getString(getColumnIndex(COLUMN_FRAME_ALL_READING));
String frameReadingNumber = getString(getColumnIndex(COLUMN_FRAME_READING_NUMBER));
String frameReference = getString(getColumnIndex(COLUMN_FRAME_REFERENCE));
String frameWritingNumber = getString(getColumnIndex(COLUMN_FRAME_WRITING_NUMBER));
frame.setZEDITION(frameEdition);
frame.setZFRAME_ID(frameId);
frame.setZFRAME_NUMBER(frameNumber);
frame.setZFRAME_TYPE(frameType);
frame.setZBOOKMARK(frameBookmark);
frame.setZGLYPH((long)frameGlyph);
frame.setZLESSON((long)frameLesson);
frame.setZALL_READING_NUMBER(frameAllReading);
frame.setZREADING_NUMBER(frameReadingNumber);
frame.setZREFERENCE(frameReference);
frame.setZWRITING_NUMBER(frameWritingNumber);
return frame;
}
}
It would be consume lot of work for doing this for every table.
So anyone could help me?
Why not using CursorLoader ? Use CursorLoader to handle the cursor query issue, and it works perfectly with CursorAdapter, Here is the google's guide
Maybe this is what you need, a light weight orm api? You can go here for more information.

Android: How to use UriMatcher to switch multiple tables, query parametes and activities?

I would like to read your thoughts on how to solve the following problem. Here are the basic requirements of the application I am working on.
Display multiple locations one city on a map.
Support for multiple cities.
Display the properties of a location on a separate details view.
Location properties of each city differ.
I would like to implement a flexible decision logic that switches between cities based on the location that the map is at. That means, the initial information I rely on, is the map center. Here is the theoretical workflow.
Get the current center location from the map.
Translate the location into a city url and uri.
Download locations via HTTP using the url.
Store the locations in local database. One table for each city since location properties differ.
Load cached or downloaded data from a content resolver using the uri.
Create overlay items and include the uri reference and a unique id.
Open a details view when tapping on a location.
The details view should render the city specific location properties.
The location properties again are loaded via a content resolver based on the passed uri and unique id.
Questions:
I am particular interested on how you would switch cities, query parameters such as column names using the UriMatcher class.
Would you prepare one details view for each city? Or do you see any practical solution to swap text fields, label, .. based on the available property information?
To illustrate the different properties, here are two example cities and a content provider.
Example:
public class DatabaseParis {
public static final class Contract {
public static final String COLUMN_LATITUDE = "latitude";
public static final String COLUMN_LONGITUDE = "longitude";
public static final String COLUMN_NAME = "name";
}
And another city ...
public class DatabaseDenver {
public static final class Contract {
public static final String COLUMN_LATITUDE = "lat";
public static final String COLUMN_LONGITUDE = "lon";
public static final String COLUMN_HEIGHT = "height";
public static final String COLUMN_DIAMETER = "diameter";
}
And a content provider ...
public class CustomContentProvider extends ContentProvider {
public static final class Contract {
public static final Uri URI_PARIS = Uri.parse("content://" + AUTHORITY + "/cities/paris");
}
private static final String AUTHORITY = "com.example.cities.locations";
private static final int URI_CODE_PARIS = 0;
private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
static {
URI_MATCHER.addURI(AUTHORITY, "cities/paris", URI_CODE_PARIS);
}
I am unsure about using one or multiple content provider since I read putting all database references into one can be a problem when the data should be synced in the future.
I guess one who deals with such a scenario should consume the following information sources.
Developing Android REST client applications, Virgil Dobjanschi, Google I/O San Francisco, 2010
ContentProvider and REST API, Benjamin Brombach, Android UserGroup Berlin, 2012

Appropriate storage and display of my bookmarks/history activity?

I want a simple bookmarks and/or history for my app, and I'm wondering what the most appropriate storage would be? A text in a text file or preference, or perhaps a database? Which would be most flexible across updates, and efficient for space and lookup time?
For the display, I'm thinking this would be a good starting point, but would it be easy to add an icon to some items?
Edit:
I finally set up a Bookmark activity that should connect to a database:
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bookmarkview);
Cursor cursor = managedQuery(getIntent().getData(), new String[] {Bookmark.TITLE, Bookmark.URL},
null, null, Bookmark.DEFAULT_SORT_ORDER);
setListAdapter(new SimpleCursorAdapter(this, R.layout.bookmarkitem, cursor,
new String[] { Bookmark.TITLE }, new int[] { android.R.id.text1 }));
findViewById(R.id.addBookmark).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
ContentValues values = new ContentValues();
values.put("url", _url);
values.put("title", _title);
// When the update completes,
// the content provider will notify the cursor of the change, which will
// cause the UI to be updated.
getContentResolver().update(_myuri, values, null, null);
}
});
}
Bookmark.java:
package com.tunes.viewer.Bookmarks;
import android.net.Uri;
import android.provider.BaseColumns;
/*
* Database will have:
* pk - primary key
* title - the name of the bookmark.
* url - the url.
*/
public class Bookmark implements BaseColumns{
public static final String AUTHORITY = "com.tunes.viewer";
/**
* The content:// style URL for this table
*/
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/Bookmarks");
/**
* The MIME type of {#link #CONTENT_URI} providing a directory of notes.
*/
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.note";
/**
* The MIME type of a {#link #CONTENT_URI} sub-directory of a single note.
*/
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.note";
/**
* The default sort order for this table
*/
public static final String DEFAULT_SORT_ORDER = "title";
/**
* The title of the note
* <P>Type: TEXT</P>
*/
public static final String TITLE = "title";
/**
* The url
* <P>Type: TEXT</P>
*/
public static final String URL = "url";
}
I seem to have fixed most of the problems I was having, but unfortunately it doesn't add to the database when I click the Add button (calling the onclick above). Furthermore, I added data to the database, but it doesn't show up in the view. What's wrong with the cursor/adapter here? Full source is here.
i would suggest, you go with database. It will be easy and efficient solution for your requirement.
A single table in sqlite will suffice to your requirements. as you will need to maintain a list of url you visited. this table will also serve your requirement of storing bookmark.
your table format could be something like this.
_____________________________________________________________________________________
Id(Auto-increment) | Title of page | Url of Page |name of icon(if needed) |isBookmark |
_____________________________________________________________________________________
This could be a good structure to achieve you requirement. set isBookmark to 0/1 to set specific link as bookmark or unbookmark it.
EDIT
I did not suggest you to use SharedPreferences and i wont (though it is straight forword and easy to implement) and reason lies in very definition of SharedPreferences which says:
"The SharedPreferences class provides a general framework that allows you to save and retrieve persistent key-value pairs of primitive data types. You can use SharedPreferences to save any primitive data: booleans, floats, ints, longs, and strings."
Now i can not imagine a single way to store ArrayList<String>(Urls) in one of these primitive datatypes.
There is one more work around.and it is Object Serialization. you can save your complete arraylist instance to a file and next time when you need this object, deseralize it similarly.. Here is the sample code for Serialization.
.
public void serializeMap(ArrayList<String> list) {
try {
FileOutputStream fStream = openFileOutput(namefile.bin, Context.MODE_PRIVATE) ;
ObjectOutputStream oStream = new ObjectOutputStream(fStream);
oStream.writeObject(list);
oStream.flush();
oStream.close();
Log.v("Serialization success", "Success");
} catch (Exception e) {
Log.v("IO Exception", e.getMessage());
}
}
But this approach is not much recommended though.
I agree with WareNinja- the SharedPreferences data areas would be sufficient for simple, non-relational data. This SO answer is very comprehensive in describing the nuances of implementing Activity and/or application-wide SharedPreferences.
The SharedPreferences framework will take care of all the data persistence minimising the amount of code you will need to write and your exposure to db-like 'update' transactions.
However be aware, in terms of expanding your application this medium is powerful but inflexible. The minute you feel the need to expand the type of data being stored move to SQLite or similar.
I suggest using SharedPreferences and/or memdiskcache, both works fast and seamlessly.
p.s. nothing against using sqlite, however i always try to avoid using db for client apps.
example lib to abstract local storage (no db!);
https://github.com/wareninja/generic-store-for-android
you can store and retrieve any type of data in key-value form,
sample code for loading java object from memdiskcache;
String keyPrefix = "blabla1";
if (GenericStore.isCustomKeyExist(GenericStore.TYPE_MEMDISKCACHE, keyPrefix, this)) {
mNewPoiDataList = (NewPoiDataList)GenericStore.getObject(GenericStore.TYPE_MEMDISKCACHE
, keyPrefix, this);
}

Categories

Resources