Showing posts with label databases. Show all posts
Showing posts with label databases. Show all posts

23 December 2013

Android show contact email addresses

So this is something in Android I thought would be really simple but quite frankly, wasn't. I want to get a list of all email addresses in my phone and display them in a list. If one is to use ContactsContract.CommonDataKinds.Email.CONTENT_URI without filter you basically get every email address you've ever emailed. Not ideal. I am (in this case) looking for only our saved Google contacts. We can do this query in the UI thread, which works fine but if you have several hundred contacts that'll kill the app. So we're going to use LoaderManager. First we setup out fragment:

public class FragmentMain extends Fragment implements LoaderManager.LoaderCallbacks{

 ArrayList mFriends = new ArrayList();

...
}

Now we need to setup our createLoader method to get the data and onLoadFinished to put the data into the UI. The selection here is very important as it limits the query to the visible contacts: String my_selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '1'";.
Next step is very simple, in the onLoadFinished we loop through the available data, adding each email address to an ArrayList.


 @Override
 public Loader onCreateLoader(int arg0, Bundle arg1) {
  //Sort by email address no case
  final String my_sort_order = ContactsContract.CommonDataKinds.Email.DATA + " COLLATE NOCASE ASC";
  String my_selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '1'";
  String[] eproj = new String[]{
   ContactsContract.Contacts._ID,
   ContactsContract.CommonDataKinds.Email.DATA};
  Uri uri = android.provider.ContactsContract.CommonDataKinds.Email.CONTENT_URI;
  //Query all emails in contacts
  return new CursorLoader(getActivity(), uri, eproj, my_selection, null, my_sort_order);
 }

 @Override
 public void onLoadFinished(Loader arg0, Cursor data) {
  
  if (data != null && data.moveToFirst()) {
   //Loop through cursor
   while (!data.isAfterLast()) {
    //get Email address
    String myemail = data.getString(data.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
    if(!mFriends.contains(myemail)){
     //Add email to arrayList
     mFriends.add(myemail);
    }
    
    data.moveToNext();
   }
  }
  //load friends into ui
  loadFriends();
 }

 @Override
 public void onLoaderReset(Loader arg0) {
  //Not Used
 }

Last but not least we load the data into our listview. Now you can of course, should you desire, create a custom Adapter and implement your own item view, but that's a blog post for another day.


 private void loadFriends(){
  //load arraylist into adapter.
  ArrayAdapter adapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, android.R.id.text1, mFriends);
  mFriendsList.setAdapter(adapter);
 }

Oh and one more thing, don't forget your permissions :)
<uses-permission android:name="android.permission.READ_CONTACTS" />

06 August 2013

Android databse SqlLite and SQL Injection

SQL Injection is one of my favourite topics, sad but true. I think SQL injection is a very clever way of deceiving apps. This then encourages developers to be equally clever and thorough in their jobs to protect their data. I'm not for a moment endorsing such practices, what I'm saying is good developers should be aware of the possibilities.

In my last blog article I wrote a very brief introduction to SqlLite in Android.
http://webdeveloperpadawan.blogspot.ca/2013/07/android-app-using-database-sqllite.html

In this I deliberately left in some weak code so I could write a follow up on SQL injection. Look carefully at this string:

String DATABASE_ADD_USER  = "insert into "  + TABLE_NAME + " (muppetname) values (";

Obviously very susceptible to injection. If a user wrote

'; drop table theusers; --

We'd have a problem. Now fortunately database.execSQL() doesn't allow us to run more than one sql command in one execution. From developer.android.com:
Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data.
In some ways this limits the potential of SQL injection, but we don't want to rely on that and it is horribly bad practice. Lets try it on our app and see what happens, paste the above (drop table statement) into the pop-up that appears when you click the btnFuzzy. You'll see your app crash and a SQLException in logCat.

In coldFusion we have a very useful tag called cfqueryparam: http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=Tags_p-q_18.html This simple tag gives us basic protection from injection and even allows us to specify the datatype. Although we should always clean our user input anyway :) Android has something very similar, allowing us to insert data using database.insert.

All we have to do is slightly ammend our insert user function:

 public void addNewUserProperly(SQLiteDatabase database, String name){
     ContentValues values = new ContentValues();
     values.put("muppetname", name);
     database.insert(TABLE_NAME, null, values);
 }

Now you'll see we've hardly changed anything, we use contentValues to store a set of values, the column name and the value. Then we insert that with database.insert. Super simple. If we re-run this and try our SQL injection trick, no more critical error :)

Hope this is of some use.

29 July 2013

Android app using database sqlLite

I created a cute little test app today to try out a few database concepts on Android. Thankfully it's really easy and there are some great tutorials out there. Anyway some of the concepts are really useful so I thought I'd jot down my findings.

First I created my new Android project ignore the MainActivity for now. I create a pretty standard Muppet.java class. I shan't patronise you with the code, int ID, String name and getters and setters for each. Then I create a new class called MySqlLiteHelper.java this is what will do the db interaction for us.

MySqlLiteHelper.java:
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class MySqlLiteHelper extends SQLiteOpenHelper {

 private static final String DATABASE_NAME  = "muppets.db";
 private static final int DATABASE_VERSION = 1;
 private static final String TABLE_NAME  = "theusers";

 // Database creation sql statement
 private static final String DATABASE_CREATE  = "create table " + TABLE_NAME + " (userid integer primary key autoincrement, muppetname text not null);";
 // DO NOT DO THIS IN YOUR CODE:
 private static final String DATABASE_ADD_USER  = "insert into "  + TABLE_NAME + " (muppetname) values (";
  
 
 public MySqlLiteHelper(Context context) {
  super(context, DATABASE_NAME, null, DATABASE_VERSION);
 }


 @Override
 public void onCreate(SQLiteDatabase database) {
  database.execSQL(DATABASE_CREATE);
 }
 

 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  Log.w(MySqlLiteHelper.class.getName(), "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data");
  db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
  onCreate(db);
 }
 
 
 public void addNewuser(SQLiteDatabase database, String name){
  // DO NOT DO INSERTS LIKE THIS IN YOUR CODE. FIND OUT WHY I THE NEXT ARTICLE.
  String insertString = DATABASE_ADD_USER + "'" + name + "');";
  database.execSQL(insertString);
 }
 
 
 public List getAllUsers(SQLiteDatabase database){
  List muppets = new ArrayList();
  String[] columns = {"userid","muppetname"};

  Cursor cursor = database.query(TABLE_NAME, columns, null, null, null, null, null);

  cursor.moveToLast();
  while (!cursor.isBeforeFirst()) {
   Muppet muppet = cursorToMuppet(cursor);
   muppets.add(muppet);
   cursor.moveToPrevious();
  }
  // Make sure to close the cursor
  cursor.close();
  return muppets;
 }
 
 
 private Muppet cursorToMuppet(Cursor cursor) {
  Muppet muppet = new Muppet();
  muppet.setMuppetId(cursor.getInt(0));
  muppet.setMuppetName(cursor.getString(1));
  return muppet;
 }
 
} 
  • MySqlLiteHelper - This function is the constructor, on initialization it will create the DB.
  • onCreate - This function created the database table by executing the static string at the top.
  • onUpgrade - I think this function is pretty clever, if you change the db version number, it'll self upgrade! Amazeballs!
  • addNewuser - This is an ugly way to insert a user, I'll change this later.
  • getAllUsers - Here we're creating a cursor and querying the db for all the users. Then we're reversing through the cursor and putting the user object into a list. I opted to reverse the list so new Muppets show up at the top. Although it's quite easy to traverse it normally and have new users at the bottom.
One quick thing that's important to mention is we're using a function in Muppet.java to force the fragment to show the muppet name, instead of the object id.

@Override
public String toString() {
 return name;
}


Our next step is to create the layout file. As an additional step I've included a fragment. This lets us compartmentalise our layout neatly. If you want to just dump a listView on the layout, you could also do that quite easily.
 <Button
  android:id="@+id/btnKermit"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignParentLeft="true"
  android:text="Insert Kermit" />

 <Button
  android:id="@+id/btnFuzzy"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignParentRight="true"
  android:text="Insert Fuzzy" />

 <Button
  android:id="@+id/btnRefresh"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_below="@+id/btnKermit"
  android:layout_centerHorizontal="true"
  android:layout_marginTop="19dp"
  android:text="Refresh" />
 
 <fragment
  android:id="@+id/fragment1"
  android:name="com.example.testdata.ShowFragment"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignParentBottom="true"
  android:layout_below="@+id/btnRefresh"
  android:layout_centerHorizontal="true" />
Notice that this fragment is pointing directly to our ShowFragment.java class which we'll create now:
import java.util.List;

import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.app.ListFragment;

public class ShowFragment extends ListFragment {

 private SQLiteDatabase database;
 private MySqlLiteHelper dbHelper;
 
 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
  super.onActivityCreated(savedInstanceState);
  
  dbHelper = new MySqlLiteHelper(getActivity());
  database = dbHelper.getWritableDatabase();
  
  showAll();
 }
 
 public void showAll(){
  List values   = dbHelper.getAllUsers(database);
  final ArrayAdapter adapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, values);
  
  setListAdapter(adapter);
 }

 @Override
 public void onListItemClick(ListView l, View v, int position, long id) {
  // Do something with the data
 }
}
This should be pretty straightforward. OnActivityCreated we get the database instance, then call showAll. showAll() calls getAllUsers and puts the results in a List. This List is then converted to an adapter and we use setListAdapter to show the results in the fragment.

Bingo!
The main activity doesn't do anything special, it has a couple of buttons for adding new muppets, basic listeners which call
dbHelper.addNewuser(database, "Kermit");

Oh and there's a refresh button which updates the fragment:
 public void refresh(){
  //get fragment to refresh
  ShowFragment viewer = (ShowFragment) getFragmentManager().findFragmentById(R.id.fragment1);
     viewer.showAll();
 }

You're done! Super easy, hope it helps.