diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index b13e074..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-bin
-gen
-*.iml
-**/build
-.gradle
diff --git a/app/build.gradle b/app/build.gradle
deleted file mode 100644
index 3fdc6a1..0000000
--- a/app/build.gradle
+++ /dev/null
@@ -1,23 +0,0 @@
-apply plugin: 'com.android.application'
-
-android {
- compileSdkVersion 17
- buildToolsVersion "21.1.2"
-
- defaultConfig {
- applicationId "com.example.providerexample"
- minSdkVersion 14
- targetSdkVersion 17
- }
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
- }
- }
-}
-
-dependencies {
- compile 'com.android.support:support-v4:18.0.0'
-}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
deleted file mode 100644
index 00f8b40..0000000
--- a/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/java/com/example/providerexample/PersonDetailActivity.java b/app/src/main/java/com/example/providerexample/PersonDetailActivity.java
deleted file mode 100644
index 36450bb..0000000
--- a/app/src/main/java/com/example/providerexample/PersonDetailActivity.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.example.providerexample;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.NavUtils;
-import android.view.MenuItem;
-
-/**
- * An activity representing a single Person detail screen. This
- * activity is only used on handset devices. On tablet-size devices,
- * item details are presented side-by-side with a list of items
- * in a {@link PersonListActivity}.
- *
- * This activity is mostly just a 'shell' activity containing nothing
- * more than a {@link PersonDetailFragment}.
- */
-public class PersonDetailActivity extends FragmentActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_person_detail);
-
- // Show the Up button in the action bar.
- getActionBar().setDisplayHomeAsUpEnabled(true);
-
- // savedInstanceState is non-null when there is fragment state
- // saved from previous configurations of this activity
- // (e.g. when rotating the screen from portrait to landscape).
- // In this case, the fragment will automatically be re-added
- // to its container so we don't need to manually add it.
- // For more information, see the Fragments API guide at:
- //
- // http://developer.android.com/guide/components/fragments.html
- //
- if (savedInstanceState == null) {
- // Create the detail fragment and add it to the activity
- // using a fragment transaction.
- Bundle arguments = new Bundle();
- arguments.putLong(PersonDetailFragment.ARG_ITEM_ID,
- getIntent().getLongExtra(PersonDetailFragment.ARG_ITEM_ID, -1));
- PersonDetailFragment fragment = new PersonDetailFragment();
- fragment.setArguments(arguments);
- getSupportFragmentManager().beginTransaction()
- .add(R.id.person_detail_container, fragment)
- .commit();
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- // This ID represents the Home or Up button. In the case of this
- // activity, the Up button is shown. Use NavUtils to allow users
- // to navigate up one level in the application structure. For
- // more details, see the Navigation pattern on Android Design:
- //
- // http://developer.android.com/design/patterns/navigation.html#up-vs-back
- //
- NavUtils.navigateUpTo(this, new Intent(this, PersonListActivity.class));
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-}
diff --git a/app/src/main/java/com/example/providerexample/PersonDetailFragment.java b/app/src/main/java/com/example/providerexample/PersonDetailFragment.java
deleted file mode 100644
index 0983be4..0000000
--- a/app/src/main/java/com/example/providerexample/PersonDetailFragment.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.example.providerexample;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import com.example.providerexample.database.DatabaseHandler;
-import com.example.providerexample.database.Person;
-
-/**
- * A fragment representing a single Person detail screen.
- * This fragment is either contained in a {@link PersonListActivity}
- * in two-pane mode (on tablets) or a {@link PersonDetailActivity}
- * on handsets.
- */
-public class PersonDetailFragment extends Fragment {
- /**
- * The fragment argument representing the item ID that this fragment
- * represents.
- */
- public static final String ARG_ITEM_ID = "item_id";
-
- /**
- * The person this fragment is presenting.
- */
- private Person mItem;
-
- /**
- * The UI elements showing the details of the Person
- */
- private TextView textFirstName;
- private TextView textLastName;
- private TextView textBio;
-
- /**
- * Mandatory empty constructor for the fragment manager to instantiate the
- * fragment (e.g. upon screen orientation changes).
- */
- public PersonDetailFragment() {
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- if (getArguments().containsKey(ARG_ITEM_ID)) {
- // Should use the contentprovider here ideally
- mItem = DatabaseHandler.getInstance(getActivity()).getPerson(getArguments().getLong(ARG_ITEM_ID));
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View rootView = inflater.inflate(R.layout.fragment_person_detail, container, false);
-
- if (mItem != null) {
- textFirstName = ((TextView) rootView.findViewById(R.id.textFirstName));
- textFirstName.setText(mItem.firstname);
-
- textLastName = ((TextView) rootView.findViewById(R.id.textLastName));
- textLastName.setText(mItem.lastname);
-
- textBio = ((TextView) rootView.findViewById(R.id.textBio));
- textBio.setText(mItem.bio);
- }
-
- return rootView;
- }
-
- @Override
- public void onPause() {
- super.onPause();
- updatePersonFromUI();
- }
-
- private void updatePersonFromUI() {
- if (mItem != null) {
- mItem.firstname = textFirstName.getText().toString();
- mItem.lastname = textLastName.getText().toString();
- mItem.bio = textBio.getText().toString();
-
- DatabaseHandler.getInstance(getActivity()).putPerson(mItem);
- }
- }
-}
diff --git a/app/src/main/java/com/example/providerexample/PersonListActivity.java b/app/src/main/java/com/example/providerexample/PersonListActivity.java
deleted file mode 100644
index 03474b0..0000000
--- a/app/src/main/java/com/example/providerexample/PersonListActivity.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package com.example.providerexample;
-
-import com.example.providerexample.database.DatabaseHandler;
-import com.example.providerexample.database.Person;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-
-/**
- * An activity representing a list of Persons. This activity has different
- * presentations for handset and tablet-size devices. On handsets, the activity
- * presents a list of items, which when touched, lead to a
- * {@link PersonDetailActivity} representing item details. On tablets, the
- * activity presents the list of items and item details side-by-side using two
- * vertical panes.
- *
- * The activity makes heavy use of fragments. The list of items is a
- * {@link PersonListFragment} and the item details (if present) is a
- * {@link PersonDetailFragment}.
- *
- * This activity also implements the required
- * {@link PersonListFragment.Callbacks} interface to listen for item selections.
- */
-public class PersonListActivity extends FragmentActivity implements
- PersonListFragment.Callbacks {
-
- /**
- * Whether or not the activity is in two-pane mode, i.e. running on a tablet
- * device.
- */
- private boolean mTwoPane;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_person_list);
-
- if (findViewById(R.id.person_detail_container) != null) {
- // The detail container view will be present only in the
- // large-screen layouts (res/values-large and
- // res/values-sw600dp). If this view is present, then the
- // activity should be in two-pane mode.
- mTwoPane = true;
-
- // In two-pane mode, list items should be given the
- // 'activated' state when touched.
- ((PersonListFragment) getSupportFragmentManager().findFragmentById(
- R.id.person_list)).setActivateOnItemClick(true);
- }
-
- // TODO: If exposing deep links into your app, handle intents here.
- }
-
- /**
- * Callback method from {@link PersonListFragment.Callbacks} indicating that
- * the item with the given ID was selected.
- */
- @Override
- public void onItemSelected(long id) {
- if (mTwoPane) {
- // In two-pane mode, show the detail view in this activity by
- // adding or replacing the detail fragment using a
- // fragment transaction.
- Bundle arguments = new Bundle();
- arguments.putLong(PersonDetailFragment.ARG_ITEM_ID, id);
- PersonDetailFragment fragment = new PersonDetailFragment();
- fragment.setArguments(arguments);
- getSupportFragmentManager().beginTransaction()
- .replace(R.id.person_detail_container, fragment).commit();
-
- } else {
- // In single-pane mode, simply start the detail activity
- // for the selected item ID.
- Intent detailIntent = new Intent(this, PersonDetailActivity.class);
- detailIntent.putExtra(PersonDetailFragment.ARG_ITEM_ID, id);
- startActivity(detailIntent);
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.list_activity, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- boolean result = false;
- if (R.id.newPerson == item.getItemId()) {
- result = true;
- // Create a new person.
- Person p = new Person();
- DatabaseHandler.getInstance(this).putPerson(p);
- // Open a new fragment with the new id
- onItemSelected(p.id);
- }
-
- return result;
- }
-}
diff --git a/app/src/main/java/com/example/providerexample/PersonListFragment.java b/app/src/main/java/com/example/providerexample/PersonListFragment.java
deleted file mode 100644
index 8fcdf5f..0000000
--- a/app/src/main/java/com/example/providerexample/PersonListFragment.java
+++ /dev/null
@@ -1,186 +0,0 @@
-package com.example.providerexample;
-
-import android.app.Activity;
-import android.support.v4.app.ListFragment;
-import android.support.v4.app.LoaderManager.LoaderCallbacks;
-import android.support.v4.content.CursorLoader;
-import android.support.v4.content.Loader;
-import android.support.v4.widget.SimpleCursorAdapter;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ListView;
-
-import com.example.providerexample.database.Person;
-import com.example.providerexample.database.PersonProvider;
-
-/**
- * A list fragment representing a list of Persons. This fragment also supports
- * tablet devices by allowing list items to be given an 'activated' state upon
- * selection. This helps indicate which item is currently being viewed in a
- * {@link PersonDetailFragment}.
- *
- * Activities containing this fragment MUST implement the {@link Callbacks}
- * interface.
- */
-public class PersonListFragment extends ListFragment {
-
- /**
- * The serialization (saved instance state) Bundle key representing the
- * activated item position. Only used on tablets.
- */
- private static final String STATE_ACTIVATED_POSITION = "activated_position";
-
- /**
- * The fragment's current callback object, which is notified of list item
- * clicks.
- */
- private Callbacks mCallbacks = sDummyCallbacks;
-
- /**
- * The current activated item position. Only used on tablets.
- */
- private int mActivatedPosition = ListView.INVALID_POSITION;
-
- /**
- * A callback interface that all activities containing this fragment must
- * implement. This mechanism allows activities to be notified of item
- * selections.
- */
- public interface Callbacks {
- /**
- * Callback for when an item has been selected.
- */
- public void onItemSelected(long l);
- }
-
- /**
- * A dummy implementation of the {@link Callbacks} interface that does
- * nothing. Used only when this fragment is not attached to an activity.
- */
- private static Callbacks sDummyCallbacks = new Callbacks() {
- @Override
- public void onItemSelected(long id) {
- }
- };
-
- /**
- * Mandatory empty constructor for the fragment manager to instantiate the
- * fragment (e.g. upon screen orientation changes).
- */
- public PersonListFragment() {
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setListAdapter(new SimpleCursorAdapter(getActivity(),
- R.layout.person_listitem, null, new String[] {
- Person.COL_FIRSTNAME, Person.COL_LASTNAME,
- Person.COL_BIO }, new int[] { R.id.cardFirstName,
- R.id.cardLastName, R.id.cardDescription }, 0));
-
- // Load the content
- getLoaderManager().initLoader(0, null, new LoaderCallbacks() {
- @Override
- public Loader onCreateLoader(int id, Bundle args) {
- return new CursorLoader(getActivity(),
- PersonProvider.URI_PERSONS, Person.FIELDS, null, null,
- null);
- }
-
- @Override
- public void onLoadFinished(Loader loader, Cursor c) {
- ((SimpleCursorAdapter) getListAdapter()).swapCursor(c);
- }
-
- @Override
- public void onLoaderReset(Loader arg0) {
- ((SimpleCursorAdapter) getListAdapter()).swapCursor(null);
- }
- });
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.fragment_person_list, null);
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- // Restore the previously serialized activated item position.
- if (savedInstanceState != null
- && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
- setActivatedPosition(savedInstanceState
- .getInt(STATE_ACTIVATED_POSITION));
- }
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- // Activities containing this fragment must implement its callbacks.
- if (!(activity instanceof Callbacks)) {
- throw new IllegalStateException(
- "Activity must implement fragment's callbacks.");
- }
-
- mCallbacks = (Callbacks) activity;
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
-
- // Reset the active callbacks interface to the dummy implementation.
- mCallbacks = sDummyCallbacks;
- }
-
- @Override
- public void onListItemClick(ListView listView, View view, int position,
- long id) {
- super.onListItemClick(listView, view, position, id);
-
- // Notify the active callbacks interface (the activity, if the
- // fragment is attached to one) that an item has been selected.
- mCallbacks.onItemSelected(getListAdapter().getItemId(position));
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- if (mActivatedPosition != ListView.INVALID_POSITION) {
- // Serialize and persist the activated item position.
- outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
- }
- }
-
- /**
- * Turns on activate-on-click mode. When this mode is on, list items will be
- * given the 'activated' state when touched.
- */
- public void setActivateOnItemClick(boolean activateOnItemClick) {
- // When setting CHOICE_MODE_SINGLE, ListView will automatically
- // give items the 'activated' state when touched.
- getListView().setChoiceMode(
- activateOnItemClick ? ListView.CHOICE_MODE_SINGLE
- : ListView.CHOICE_MODE_NONE);
- }
-
- private void setActivatedPosition(int position) {
- if (position == ListView.INVALID_POSITION) {
- getListView().setItemChecked(mActivatedPosition, false);
- } else {
- getListView().setItemChecked(position, true);
- }
-
- mActivatedPosition = position;
- }
-}
diff --git a/app/src/main/java/com/example/providerexample/database/DatabaseHandler.java b/app/src/main/java/com/example/providerexample/database/DatabaseHandler.java
deleted file mode 100644
index cf27cc2..0000000
--- a/app/src/main/java/com/example/providerexample/database/DatabaseHandler.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package com.example.providerexample.database;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-
-public class DatabaseHandler extends SQLiteOpenHelper {
-
- private static DatabaseHandler singleton;
-
- public static DatabaseHandler getInstance(final Context context) {
- if (singleton == null) {
- singleton = new DatabaseHandler(context);
- }
- return singleton;
- }
-
- private static final int DATABASE_VERSION = 1;
- private static final String DATABASE_NAME = "providerExample";
-
- private final Context context;
-
- public DatabaseHandler(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- // Good idea to have the context that doesn't die with the window
- this.context = context.getApplicationContext();
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL(Person.CREATE_TABLE);
-
- Person person = new Person();
- person.firstname = "Sylvester";
- person.lastname = "Stallone";
- person.bio = "...";
- db.insert(Person.TABLE_NAME, null, person.getContent());
-
- person.firstname = "Danny";
- person.lastname = "DeVito";
- person.bio = "...";
- db.insert(Person.TABLE_NAME, null, person.getContent());
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- }
-
- public synchronized Person getPerson(final long id) {
- final SQLiteDatabase db = this.getReadableDatabase();
- final Cursor cursor = db.query(Person.TABLE_NAME, Person.FIELDS,
- Person.COL_ID + " IS ?", new String[] { String.valueOf(id) },
- null, null, null, null);
- if (cursor == null || cursor.isAfterLast()) {
- return null;
- }
-
- Person item = null;
- if (cursor.moveToFirst()) {
- item = new Person(cursor);
- }
- cursor.close();
- return item;
- }
-
- public synchronized boolean putPerson(final Person person) {
- boolean success = false;
- int result = 0;
- final SQLiteDatabase db = this.getWritableDatabase();
-
- if (person.id > -1) {
- result += db.update(Person.TABLE_NAME, person.getContent(),
- Person.COL_ID + " IS ?",
- new String[] { String.valueOf(person.id) });
- }
-
- if (result > 0) {
- success = true;
- } else {
- // Update failed or wasn't possible, insert instead
- final long id = db.insert(Person.TABLE_NAME, null,
- person.getContent());
-
- if (id > -1) {
- person.id = id;
- success = true;
- }
- }
-
- if (success) {
- notifyProviderOnPersonChange();
- }
-
- return success;
- }
-
- public synchronized int removePerson(final Person person) {
- final SQLiteDatabase db = this.getWritableDatabase();
- final int result = db.delete(Person.TABLE_NAME,
- Person.COL_ID + " IS ?",
- new String[] { Long.toString(person.id) });
-
- if (result > 0) {
- notifyProviderOnPersonChange();
- }
- return result;
- }
-
- private void notifyProviderOnPersonChange() {
- context.getContentResolver().notifyChange(
- PersonProvider.URI_PERSONS, null, false);
- }
-}
diff --git a/app/src/main/java/com/example/providerexample/database/Person.java b/app/src/main/java/com/example/providerexample/database/Person.java
deleted file mode 100644
index 9b9511b..0000000
--- a/app/src/main/java/com/example/providerexample/database/Person.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.example.providerexample.database;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-
-/**
- * A class representation of a row in table "Person".
- */
-public class Person {
-
- // SQL convention says Table name should be "singular", so not Persons
- public static final String TABLE_NAME = "Person";
- // Naming the id column with an underscore is good to be consistent
- // with other Android things. This is ALWAYS needed
- public static final String COL_ID = "_id";
- // These fields can be anything you want.
- public static final String COL_FIRSTNAME = "firstname";
- public static final String COL_LASTNAME = "lastname";
- public static final String COL_BIO = "bio";
-
- // For database projection so order is consistent
- public static final String[] FIELDS = { COL_ID, COL_FIRSTNAME, COL_LASTNAME,
- COL_BIO };
-
- /*
- * The SQL code that creates a Table for storing Persons in.
- * Note that the last row does NOT end in a comma like the others.
- * This is a common source of error.
- */
- public static final String CREATE_TABLE =
- "CREATE TABLE " + TABLE_NAME + "("
- + COL_ID + " INTEGER PRIMARY KEY,"
- + COL_FIRSTNAME + " TEXT NOT NULL DEFAULT '',"
- + COL_LASTNAME + " TEXT NOT NULL DEFAULT '',"
- + COL_BIO + " TEXT NOT NULL DEFAULT ''"
- + ")";
-
- // Fields corresponding to database columns
- public long id = -1;
- public String firstname = "";
- public String lastname = "";
- public String bio = "";
-
- /**
- * No need to do anything, fields are already set to default values above
- */
- public Person() {
- }
-
- /**
- * Convert information from the database into a Person object.
- */
- public Person(final Cursor cursor) {
- // Indices expected to match order in FIELDS!
- this.id = cursor.getLong(0);
- this.firstname = cursor.getString(1);
- this.lastname = cursor.getString(2);
- this.bio = cursor.getString(3);
- }
-
- /**
- * Return the fields in a ContentValues object, suitable for insertion
- * into the database.
- */
- public ContentValues getContent() {
- final ContentValues values = new ContentValues();
- // Note that ID is NOT included here
- values.put(COL_FIRSTNAME, firstname);
- values.put(COL_LASTNAME, lastname);
- values.put(COL_BIO, bio);
-
- return values;
- }
-}
diff --git a/app/src/main/java/com/example/providerexample/database/PersonProvider.java b/app/src/main/java/com/example/providerexample/database/PersonProvider.java
deleted file mode 100644
index c046e4f..0000000
--- a/app/src/main/java/com/example/providerexample/database/PersonProvider.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.example.providerexample.database;
-
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class PersonProvider extends ContentProvider {
-
- // All URIs share these parts
- public static final String AUTHORITY = "com.example.providerexample.provider";
- public static final String SCHEME = "content://";
-
- // URIs
- // Used for all persons
- public static final String PERSONS = SCHEME + AUTHORITY + "/person";
- public static final Uri URI_PERSONS = Uri.parse(PERSONS);
- // Used for a single person, just add the id to the end
- public static final String PERSON_BASE = PERSONS + "/";
-
- public PersonProvider() {
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- // Implement this to handle requests to delete one or more rows.
- throw new UnsupportedOperationException("Not yet implemented");
- }
-
- @Override
- public String getType(Uri uri) {
- // TODO: Implement this to handle requests for the MIME type of the data
- // at the given URI.
- throw new UnsupportedOperationException("Not yet implemented");
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- // TODO: Implement this to handle requests to insert a new row.
- throw new UnsupportedOperationException("Not yet implemented");
- }
-
- @Override
- public boolean onCreate() {
- return true;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- Cursor result = null;
- if (URI_PERSONS.equals(uri)) {
- result = DatabaseHandler
- .getInstance(getContext())
- .getReadableDatabase()
- .query(Person.TABLE_NAME, Person.FIELDS, null, null, null,
- null, null, null);
- result.setNotificationUri(getContext().getContentResolver(), URI_PERSONS);
- } else if (uri.toString().startsWith(PERSON_BASE)) {
- final long id = Long.parseLong(uri.getLastPathSegment());
- result = DatabaseHandler
- .getInstance(getContext())
- .getReadableDatabase()
- .query(Person.TABLE_NAME, Person.FIELDS,
- Person.COL_ID + " IS ?",
- new String[] { String.valueOf(id) }, null, null,
- null, null);
- result.setNotificationUri(getContext().getContentResolver(), URI_PERSONS);
- } else {
- throw new UnsupportedOperationException("Not yet implemented");
- }
-
- return result;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection,
- String[] selectionArgs) {
- // TODO: Implement this to handle requests to update one or more rows.
- throw new UnsupportedOperationException("Not yet implemented");
- }
-}
diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 2981225..0000000
Binary files a/app/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/drawable-ldpi/ic_launcher.png b/app/src/main/res/drawable-ldpi/ic_launcher.png
deleted file mode 100644
index 8eeade2..0000000
Binary files a/app/src/main/res/drawable-ldpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_launcher.png b/app/src/main/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index be5c15d..0000000
Binary files a/app/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_launcher.png b/app/src/main/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index ef17472..0000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/drawable/rounded_corners_white.xml b/app/src/main/res/drawable/rounded_corners_white.xml
deleted file mode 100644
index 05e99f4..0000000
--- a/app/src/main/res/drawable/rounded_corners_white.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_person_detail.xml b/app/src/main/res/layout/activity_person_detail.xml
deleted file mode 100644
index 3b468f8..0000000
--- a/app/src/main/res/layout/activity_person_detail.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/app/src/main/res/layout/activity_person_list.xml b/app/src/main/res/layout/activity_person_list.xml
deleted file mode 100644
index 811c990..0000000
--- a/app/src/main/res/layout/activity_person_list.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
diff --git a/app/src/main/res/layout/activity_person_twopane.xml b/app/src/main/res/layout/activity_person_twopane.xml
deleted file mode 100644
index a0e6d75..0000000
--- a/app/src/main/res/layout/activity_person_twopane.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_person_detail.xml b/app/src/main/res/layout/fragment_person_detail.xml
deleted file mode 100644
index 1b1ada2..0000000
--- a/app/src/main/res/layout/fragment_person_detail.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_person_list.xml b/app/src/main/res/layout/fragment_person_list.xml
deleted file mode 100644
index e231db1..0000000
--- a/app/src/main/res/layout/fragment_person_list.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
diff --git a/app/src/main/res/layout/person_listitem.xml b/app/src/main/res/layout/person_listitem.xml
deleted file mode 100644
index 3c8fc2f..0000000
--- a/app/src/main/res/layout/person_listitem.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/list_activity.xml b/app/src/main/res/menu/list_activity.xml
deleted file mode 100644
index e9c2f04..0000000
--- a/app/src/main/res/menu/list_activity.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values-large/refs.xml b/app/src/main/res/values-large/refs.xml
deleted file mode 100644
index 4661785..0000000
--- a/app/src/main/res/values-large/refs.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- @layout/activity_person_twopane
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values-sw600dp/refs.xml b/app/src/main/res/values-sw600dp/refs.xml
deleted file mode 100644
index 4661785..0000000
--- a/app/src/main/res/values-sw600dp/refs.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- @layout/activity_person_twopane
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values-v11/styles.xml b/app/src/main/res/values-v11/styles.xml
deleted file mode 100644
index 541752f..0000000
--- a/app/src/main/res/values-v11/styles.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values-v14/styles.xml b/app/src/main/res/values-v14/styles.xml
deleted file mode 100644
index f20e015..0000000
--- a/app/src/main/res/values-v14/styles.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
deleted file mode 100644
index 68b463d..0000000
--- a/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
- ProviderExample
- Person Detail
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
deleted file mode 100644
index 4a10ca4..0000000
--- a/app/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index c447727..0000000
--- a/build.gradle
+++ /dev/null
@@ -1,15 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-buildscript {
- repositories {
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:1.0.1'
- }
-}
-
-allprojects {
- repositories {
- jcenter()
- }
-}
diff --git a/readme_img/cardItem.png b/cardItem.png
similarity index 100%
rename from readme_img/cardItem.png
rename to cardItem.png
diff --git a/readme_img/changetolongarg.png b/changetolongarg.png
similarity index 100%
rename from readme_img/changetolongarg.png
rename to changetolongarg.png
diff --git a/fonts/OpenSans-Bold-webfont.eot b/fonts/OpenSans-Bold-webfont.eot
new file mode 100644
index 0000000..e1c7674
Binary files /dev/null and b/fonts/OpenSans-Bold-webfont.eot differ
diff --git a/fonts/OpenSans-Bold-webfont.svg b/fonts/OpenSans-Bold-webfont.svg
new file mode 100644
index 0000000..364b368
--- /dev/null
+++ b/fonts/OpenSans-Bold-webfont.svg
@@ -0,0 +1,146 @@
+
+
+
\ No newline at end of file
diff --git a/fonts/OpenSans-Bold-webfont.ttf b/fonts/OpenSans-Bold-webfont.ttf
new file mode 100644
index 0000000..2d94f06
Binary files /dev/null and b/fonts/OpenSans-Bold-webfont.ttf differ
diff --git a/fonts/OpenSans-Bold-webfont.woff b/fonts/OpenSans-Bold-webfont.woff
new file mode 100644
index 0000000..cd86852
Binary files /dev/null and b/fonts/OpenSans-Bold-webfont.woff differ
diff --git a/fonts/OpenSans-BoldItalic-webfont.eot b/fonts/OpenSans-BoldItalic-webfont.eot
new file mode 100644
index 0000000..f44ac9a
Binary files /dev/null and b/fonts/OpenSans-BoldItalic-webfont.eot differ
diff --git a/fonts/OpenSans-BoldItalic-webfont.svg b/fonts/OpenSans-BoldItalic-webfont.svg
new file mode 100644
index 0000000..8392240
--- /dev/null
+++ b/fonts/OpenSans-BoldItalic-webfont.svg
@@ -0,0 +1,146 @@
+
+
+
\ No newline at end of file
diff --git a/fonts/OpenSans-BoldItalic-webfont.ttf b/fonts/OpenSans-BoldItalic-webfont.ttf
new file mode 100644
index 0000000..f74e0e3
Binary files /dev/null and b/fonts/OpenSans-BoldItalic-webfont.ttf differ
diff --git a/fonts/OpenSans-BoldItalic-webfont.woff b/fonts/OpenSans-BoldItalic-webfont.woff
new file mode 100644
index 0000000..f3248c1
Binary files /dev/null and b/fonts/OpenSans-BoldItalic-webfont.woff differ
diff --git a/fonts/OpenSans-Italic-webfont.eot b/fonts/OpenSans-Italic-webfont.eot
new file mode 100644
index 0000000..277c189
Binary files /dev/null and b/fonts/OpenSans-Italic-webfont.eot differ
diff --git a/fonts/OpenSans-Italic-webfont.svg b/fonts/OpenSans-Italic-webfont.svg
new file mode 100644
index 0000000..29c7497
--- /dev/null
+++ b/fonts/OpenSans-Italic-webfont.svg
@@ -0,0 +1,146 @@
+
+
+
\ No newline at end of file
diff --git a/fonts/OpenSans-Italic-webfont.ttf b/fonts/OpenSans-Italic-webfont.ttf
new file mode 100644
index 0000000..63f187e
Binary files /dev/null and b/fonts/OpenSans-Italic-webfont.ttf differ
diff --git a/fonts/OpenSans-Italic-webfont.woff b/fonts/OpenSans-Italic-webfont.woff
new file mode 100644
index 0000000..469a29b
Binary files /dev/null and b/fonts/OpenSans-Italic-webfont.woff differ
diff --git a/fonts/OpenSans-Light-webfont.eot b/fonts/OpenSans-Light-webfont.eot
new file mode 100644
index 0000000..837daab
Binary files /dev/null and b/fonts/OpenSans-Light-webfont.eot differ
diff --git a/fonts/OpenSans-Light-webfont.svg b/fonts/OpenSans-Light-webfont.svg
new file mode 100644
index 0000000..bdb6726
--- /dev/null
+++ b/fonts/OpenSans-Light-webfont.svg
@@ -0,0 +1,146 @@
+
+
+
\ No newline at end of file
diff --git a/fonts/OpenSans-Light-webfont.ttf b/fonts/OpenSans-Light-webfont.ttf
new file mode 100644
index 0000000..b50ef9d
Binary files /dev/null and b/fonts/OpenSans-Light-webfont.ttf differ
diff --git a/fonts/OpenSans-Light-webfont.woff b/fonts/OpenSans-Light-webfont.woff
new file mode 100644
index 0000000..99514d1
Binary files /dev/null and b/fonts/OpenSans-Light-webfont.woff differ
diff --git a/fonts/OpenSans-LightItalic-webfont.eot b/fonts/OpenSans-LightItalic-webfont.eot
new file mode 100644
index 0000000..f0ebf2c
Binary files /dev/null and b/fonts/OpenSans-LightItalic-webfont.eot differ
diff --git a/fonts/OpenSans-LightItalic-webfont.svg b/fonts/OpenSans-LightItalic-webfont.svg
new file mode 100644
index 0000000..60765da
--- /dev/null
+++ b/fonts/OpenSans-LightItalic-webfont.svg
@@ -0,0 +1,146 @@
+
+
+
\ No newline at end of file
diff --git a/fonts/OpenSans-LightItalic-webfont.ttf b/fonts/OpenSans-LightItalic-webfont.ttf
new file mode 100644
index 0000000..5898c8c
Binary files /dev/null and b/fonts/OpenSans-LightItalic-webfont.ttf differ
diff --git a/fonts/OpenSans-LightItalic-webfont.woff b/fonts/OpenSans-LightItalic-webfont.woff
new file mode 100644
index 0000000..9c978dc
Binary files /dev/null and b/fonts/OpenSans-LightItalic-webfont.woff differ
diff --git a/fonts/OpenSans-Regular-webfont.eot b/fonts/OpenSans-Regular-webfont.eot
new file mode 100644
index 0000000..dd6fd2c
Binary files /dev/null and b/fonts/OpenSans-Regular-webfont.eot differ
diff --git a/fonts/OpenSans-Regular-webfont.svg b/fonts/OpenSans-Regular-webfont.svg
new file mode 100644
index 0000000..01038bb
--- /dev/null
+++ b/fonts/OpenSans-Regular-webfont.svg
@@ -0,0 +1,146 @@
+
+
+
\ No newline at end of file
diff --git a/fonts/OpenSans-Regular-webfont.ttf b/fonts/OpenSans-Regular-webfont.ttf
new file mode 100644
index 0000000..05951e7
Binary files /dev/null and b/fonts/OpenSans-Regular-webfont.ttf differ
diff --git a/fonts/OpenSans-Regular-webfont.woff b/fonts/OpenSans-Regular-webfont.woff
new file mode 100644
index 0000000..274664b
Binary files /dev/null and b/fonts/OpenSans-Regular-webfont.woff differ
diff --git a/fonts/OpenSans-Semibold-webfont.eot b/fonts/OpenSans-Semibold-webfont.eot
new file mode 100644
index 0000000..289aade
Binary files /dev/null and b/fonts/OpenSans-Semibold-webfont.eot differ
diff --git a/fonts/OpenSans-Semibold-webfont.svg b/fonts/OpenSans-Semibold-webfont.svg
new file mode 100644
index 0000000..cc2ca42
--- /dev/null
+++ b/fonts/OpenSans-Semibold-webfont.svg
@@ -0,0 +1,146 @@
+
+
+
\ No newline at end of file
diff --git a/fonts/OpenSans-Semibold-webfont.ttf b/fonts/OpenSans-Semibold-webfont.ttf
new file mode 100644
index 0000000..6f15073
Binary files /dev/null and b/fonts/OpenSans-Semibold-webfont.ttf differ
diff --git a/fonts/OpenSans-Semibold-webfont.woff b/fonts/OpenSans-Semibold-webfont.woff
new file mode 100644
index 0000000..4e47cb1
Binary files /dev/null and b/fonts/OpenSans-Semibold-webfont.woff differ
diff --git a/fonts/OpenSans-SemiboldItalic-webfont.eot b/fonts/OpenSans-SemiboldItalic-webfont.eot
new file mode 100644
index 0000000..50a8a6f
Binary files /dev/null and b/fonts/OpenSans-SemiboldItalic-webfont.eot differ
diff --git a/fonts/OpenSans-SemiboldItalic-webfont.svg b/fonts/OpenSans-SemiboldItalic-webfont.svg
new file mode 100644
index 0000000..65b50e2
--- /dev/null
+++ b/fonts/OpenSans-SemiboldItalic-webfont.svg
@@ -0,0 +1,146 @@
+
+
+
\ No newline at end of file
diff --git a/fonts/OpenSans-SemiboldItalic-webfont.ttf b/fonts/OpenSans-SemiboldItalic-webfont.ttf
new file mode 100644
index 0000000..55ba312
Binary files /dev/null and b/fonts/OpenSans-SemiboldItalic-webfont.ttf differ
diff --git a/fonts/OpenSans-SemiboldItalic-webfont.woff b/fonts/OpenSans-SemiboldItalic-webfont.woff
new file mode 100644
index 0000000..0adc6df
Binary files /dev/null and b/fonts/OpenSans-SemiboldItalic-webfont.woff differ
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 8c0fb64..0000000
Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 0c71e76..0000000
--- a/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-#Wed Apr 10 15:27:10 PDT 2013
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
diff --git a/gradlew b/gradlew
deleted file mode 100755
index 91a7e26..0000000
--- a/gradlew
+++ /dev/null
@@ -1,164 +0,0 @@
-#!/usr/bin/env bash
-
-##############################################################################
-##
-## Gradle start up script for UN*X
-##
-##############################################################################
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn ( ) {
- echo "$*"
-}
-
-die ( ) {
- echo
- echo "$*"
- echo
- exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
-esac
-
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
- fi
- i=$((i+1))
- done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
-fi
-
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
-}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
-
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
deleted file mode 100644
index 8a0b282..0000000
--- a/gradlew.bat
+++ /dev/null
@@ -1,90 +0,0 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/images/bullet.png b/images/bullet.png
new file mode 100644
index 0000000..22ea543
Binary files /dev/null and b/images/bullet.png differ
diff --git a/images/hr.gif b/images/hr.gif
new file mode 100644
index 0000000..bdb4168
Binary files /dev/null and b/images/hr.gif differ
diff --git a/images/nav-bg.gif b/images/nav-bg.gif
new file mode 100644
index 0000000..4743965
Binary files /dev/null and b/images/nav-bg.gif differ
diff --git a/javascripts/respond.js b/javascripts/respond.js
new file mode 100644
index 0000000..76bc260
--- /dev/null
+++ b/javascripts/respond.js
@@ -0,0 +1,779 @@
+if(typeof Object.create!=="function"){
+Object.create=function(o){
+function F(){
+};
+F.prototype=o;
+return new F();
+};
+}
+var ua={toString:function(){
+return navigator.userAgent;
+},test:function(s){
+return this.toString().toLowerCase().indexOf(s.toLowerCase())>-1;
+}};
+ua.version=(ua.toString().toLowerCase().match(/[\s\S]+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1];
+ua.webkit=ua.test("webkit");
+ua.gecko=ua.test("gecko")&&!ua.webkit;
+ua.opera=ua.test("opera");
+ua.ie=ua.test("msie")&&!ua.opera;
+ua.ie6=ua.ie&&document.compatMode&&typeof document.documentElement.style.maxHeight==="undefined";
+ua.ie7=ua.ie&&document.documentElement&&typeof document.documentElement.style.maxHeight!=="undefined"&&typeof XDomainRequest==="undefined";
+ua.ie8=ua.ie&&typeof XDomainRequest!=="undefined";
+var domReady=function(){
+var _1=[];
+var _2=function(){
+if(!arguments.callee.done){
+arguments.callee.done=true;
+for(var i=0;i<_1.length;i++){
+_1[i]();
+}
+}
+};
+if(document.addEventListener){
+document.addEventListener("DOMContentLoaded",_2,false);
+}
+if(ua.ie){
+(function(){
+try{
+document.documentElement.doScroll("left");
+}
+catch(e){
+setTimeout(arguments.callee,50);
+return;
+}
+_2();
+})();
+document.onreadystatechange=function(){
+if(document.readyState==="complete"){
+document.onreadystatechange=null;
+_2();
+}
+};
+}
+if(ua.webkit&&document.readyState){
+(function(){
+if(document.readyState!=="loading"){
+_2();
+}else{
+setTimeout(arguments.callee,10);
+}
+})();
+}
+window.onload=_2;
+return function(fn){
+if(typeof fn==="function"){
+_1[_1.length]=fn;
+}
+return fn;
+};
+}();
+var cssHelper=function(){
+var _3={BLOCKS:/[^\s{][^{]*\{(?:[^{}]*\{[^{}]*\}[^{}]*|[^{}]*)*\}/g,BLOCKS_INSIDE:/[^\s{][^{]*\{[^{}]*\}/g,DECLARATIONS:/[a-zA-Z\-]+[^;]*:[^;]+;/g,RELATIVE_URLS:/url\(['"]?([^\/\)'"][^:\)'"]+)['"]?\)/g,REDUNDANT_COMPONENTS:/(?:\/\*([^*\\\\]|\*(?!\/))+\*\/|@import[^;]+;)/g,REDUNDANT_WHITESPACE:/\s*(,|:|;|\{|\})\s*/g,MORE_WHITESPACE:/\s{2,}/g,FINAL_SEMICOLONS:/;\}/g,NOT_WHITESPACE:/\S+/g};
+var _4,_5=false;
+var _6=[];
+var _7=function(fn){
+if(typeof fn==="function"){
+_6[_6.length]=fn;
+}
+};
+var _8=function(){
+for(var i=0;i<_6.length;i++){
+_6[i](_4);
+}
+};
+var _9={};
+var _a=function(n,v){
+if(_9[n]){
+var _b=_9[n].listeners;
+if(_b){
+for(var i=0;i<_b.length;i++){
+_b[i](v);
+}
+}
+}
+};
+var _c=function(_d,_e,_f){
+if(ua.ie&&!window.XMLHttpRequest){
+window.XMLHttpRequest=function(){
+return new ActiveXObject("Microsoft.XMLHTTP");
+};
+}
+if(!XMLHttpRequest){
+return "";
+}
+var r=new XMLHttpRequest();
+try{
+r.open("get",_d,true);
+r.setRequestHeader("X_REQUESTED_WITH","XMLHttpRequest");
+}
+catch(e){
+_f();
+return;
+}
+var _10=false;
+setTimeout(function(){
+_10=true;
+},5000);
+document.documentElement.style.cursor="progress";
+r.onreadystatechange=function(){
+if(r.readyState===4&&!_10){
+if(!r.status&&location.protocol==="file:"||(r.status>=200&&r.status<300)||r.status===304||navigator.userAgent.indexOf("Safari")>-1&&typeof r.status==="undefined"){
+_e(r.responseText);
+}else{
+_f();
+}
+document.documentElement.style.cursor="";
+r=null;
+}
+};
+r.send("");
+};
+var _11=function(_12){
+_12=_12.replace(_3.REDUNDANT_COMPONENTS,"");
+_12=_12.replace(_3.REDUNDANT_WHITESPACE,"$1");
+_12=_12.replace(_3.MORE_WHITESPACE," ");
+_12=_12.replace(_3.FINAL_SEMICOLONS,"}");
+return _12;
+};
+var _13={mediaQueryList:function(s){
+var o={};
+var idx=s.indexOf("{");
+var lt=s.substring(0,idx);
+s=s.substring(idx+1,s.length-1);
+var mqs=[],rs=[];
+var qts=lt.toLowerCase().substring(7).split(",");
+for(var i=0;i-1&&_23.href&&_23.href.length!==0&&!_23.disabled){
+_1f[_1f.length]=_23;
+}
+}
+if(_1f.length>0){
+var c=0;
+var _24=function(){
+c++;
+if(c===_1f.length){
+_20();
+}
+};
+var _25=function(_26){
+var _27=_26.href;
+_c(_27,function(_28){
+_28=_11(_28).replace(_3.RELATIVE_URLS,"url("+_27.substring(0,_27.lastIndexOf("/"))+"/$1)");
+_26.cssHelperText=_28;
+_24();
+},_24);
+};
+for(i=0;i<_1f.length;i++){
+_25(_1f[i]);
+}
+}else{
+_20();
+}
+};
+var _29={mediaQueryLists:"array",rules:"array",selectors:"object",declarations:"array",properties:"object"};
+var _2a={mediaQueryLists:null,rules:null,selectors:null,declarations:null,properties:null};
+var _2b=function(_2c,v){
+if(_2a[_2c]!==null){
+if(_29[_2c]==="array"){
+return (_2a[_2c]=_2a[_2c].concat(v));
+}else{
+var c=_2a[_2c];
+for(var n in v){
+if(v.hasOwnProperty(n)){
+if(!c[n]){
+c[n]=v[n];
+}else{
+c[n]=c[n].concat(v[n]);
+}
+}
+}
+return c;
+}
+}
+};
+var _2d=function(_2e){
+_2a[_2e]=(_29[_2e]==="array")?[]:{};
+for(var i=0;i<_4.length;i++){
+_2b(_2e,_4[i].cssHelperParsed[_2e]);
+}
+return _2a[_2e];
+};
+domReady(function(){
+var els=document.body.getElementsByTagName("*");
+for(var i=0;i=_44)||(max&&_46<_44)||(!min&&!max&&_46===_44));
+}else{
+return false;
+}
+}else{
+return _46>0;
+}
+}else{
+if("device-height"===_41.substring(l-13,l)){
+_47=screen.height;
+if(_42!==null){
+if(_43==="length"){
+return ((min&&_47>=_44)||(max&&_47<_44)||(!min&&!max&&_47===_44));
+}else{
+return false;
+}
+}else{
+return _47>0;
+}
+}else{
+if("width"===_41.substring(l-5,l)){
+_46=document.documentElement.clientWidth||document.body.clientWidth;
+if(_42!==null){
+if(_43==="length"){
+return ((min&&_46>=_44)||(max&&_46<_44)||(!min&&!max&&_46===_44));
+}else{
+return false;
+}
+}else{
+return _46>0;
+}
+}else{
+if("height"===_41.substring(l-6,l)){
+_47=document.documentElement.clientHeight||document.body.clientHeight;
+if(_42!==null){
+if(_43==="length"){
+return ((min&&_47>=_44)||(max&&_47<_44)||(!min&&!max&&_47===_44));
+}else{
+return false;
+}
+}else{
+return _47>0;
+}
+}else{
+if("device-aspect-ratio"===_41.substring(l-19,l)){
+return _43==="aspect-ratio"&&screen.width*_44[1]===screen.height*_44[0];
+}else{
+if("color-index"===_41.substring(l-11,l)){
+var _48=Math.pow(2,screen.colorDepth);
+if(_42!==null){
+if(_43==="absolute"){
+return ((min&&_48>=_44)||(max&&_48<_44)||(!min&&!max&&_48===_44));
+}else{
+return false;
+}
+}else{
+return _48>0;
+}
+}else{
+if("color"===_41.substring(l-5,l)){
+var _49=screen.colorDepth;
+if(_42!==null){
+if(_43==="absolute"){
+return ((min&&_49>=_44)||(max&&_49<_44)||(!min&&!max&&_49===_44));
+}else{
+return false;
+}
+}else{
+return _49>0;
+}
+}else{
+if("resolution"===_41.substring(l-10,l)){
+var res;
+if(_45==="dpcm"){
+res=_3d("1cm");
+}else{
+res=_3d("1in");
+}
+if(_42!==null){
+if(_43==="resolution"){
+return ((min&&res>=_44)||(max&&res<_44)||(!min&&!max&&res===_44));
+}else{
+return false;
+}
+}else{
+return res>0;
+}
+}else{
+return false;
+}
+}
+}
+}
+}
+}
+}
+}
+};
+var _4a=function(mq){
+var _4b=mq.getValid();
+var _4c=mq.getExpressions();
+var l=_4c.length;
+if(l>0){
+for(var i=0;i0){
+s[c++]=",";
+}
+s[c++]=n;
+}
+}
+if(s.length>0){
+_39[_39.length]=cssHelper.addStyle("@media "+s.join("")+"{"+mql.getCssText()+"}",false);
+}
+};
+var _4e=function(_4f){
+for(var i=0;i<_4f.length;i++){
+_4d(_4f[i]);
+}
+if(ua.ie){
+document.documentElement.style.display="block";
+setTimeout(function(){
+document.documentElement.style.display="";
+},0);
+setTimeout(function(){
+cssHelper.broadcast("cssMediaQueriesTested");
+},100);
+}else{
+cssHelper.broadcast("cssMediaQueriesTested");
+}
+};
+var _50=function(){
+for(var i=0;i<_39.length;i++){
+cssHelper.removeStyle(_39[i]);
+}
+_39=[];
+cssHelper.mediaQueryLists(_4e);
+};
+var _51=0;
+var _52=function(){
+var _53=cssHelper.getViewportWidth();
+var _54=cssHelper.getViewportHeight();
+if(ua.ie){
+var el=document.createElement("div");
+el.style.position="absolute";
+el.style.top="-9999em";
+el.style.overflow="scroll";
+document.body.appendChild(el);
+_51=el.offsetWidth-el.clientWidth;
+document.body.removeChild(el);
+}
+var _55;
+var _56=function(){
+var vpw=cssHelper.getViewportWidth();
+var vph=cssHelper.getViewportHeight();
+if(Math.abs(vpw-_53)>_51||Math.abs(vph-_54)>_51){
+_53=vpw;
+_54=vph;
+clearTimeout(_55);
+_55=setTimeout(function(){
+if(!_3a()){
+_50();
+}else{
+cssHelper.broadcast("cssMediaQueriesTested");
+}
+},500);
+}
+};
+window.onresize=function(){
+var x=window.onresize||function(){
+};
+return function(){
+x();
+_56();
+};
+}();
+};
+var _57=document.documentElement;
+_57.style.marginLeft="-32767px";
+setTimeout(function(){
+_57.style.marginTop="";
+},20000);
+return function(){
+if(!_3a()){
+cssHelper.addListener("newStyleParsed",function(el){
+_4e(el.cssHelperParsed.mediaQueryLists);
+});
+cssHelper.addListener("cssMediaQueriesTested",function(){
+if(ua.ie){
+_57.style.width="1px";
+}
+setTimeout(function(){
+_57.style.width="";
+_57.style.marginLeft="";
+},0);
+cssHelper.removeListener("cssMediaQueriesTested",arguments.callee);
+});
+_3c();
+_50();
+}else{
+_57.style.marginLeft="";
+}
+_52();
+};
+}());
+try{
+document.execCommand("BackgroundImageCache",false,true);
+}
+catch(e){
+}
+
diff --git a/readme.md b/lists_sqlite_providers.md
similarity index 64%
rename from readme.md
rename to lists_sqlite_providers.md
index 4505755..1833451 100755
--- a/readme.md
+++ b/lists_sqlite_providers.md
@@ -1,49 +1,17 @@
# Things I wish I'd known about sooner: Lists, SQLite and ContentProviders
-This tutorial is good if you want to learn about SQLite and how to use it effectively
-in Android. I have upgraded the project to Android Studio so some of the
-Eclipse-centric content is slightly out-dated, but the gist of it is the same.
-All the same functionality is present in Android Studio as it was in Eclipse,
-with the same kind of wizards etc. You can also enable a setting in Android Studio
-so most of the key commands are the same.
-
## Introduction
Lists must be one of the most ubiquitous UI-elements. What app doesn't have them?
If they don't they probably have some kind of grid view. This tutorial will apply
-to them both. The final result will look like this:
-
-
-
-
-
-The structure of the tutorial might not be common. I am going to start by
-creating the app, documenting all the steps on the way. Once that's done,
-I will explain some things in more detail.
-
-To start with, we're going to have to start a new project. This means there
-will be a small amount of boiler plate to deal with before we can actually
-get our code running.
-
-Somewhere in the middle, I will be taking a detour to make those nice looking layouts.
-If you don't care about the layout stuff, just skip that section.
-
-The final step is to make the app use the new layouts, and load the data
-from our database into them.
-
-Once the app is complete, I can explain a few things in more detail by
-pointing to the code just created.
-
+to them both.
### Motivation
Many tutorials only show how to use ArrayAdapters and I find that problematic.
ArrayAdapters are fine if you're showing a static list, but I think most devs
have something more dynamic in mind. Simple rule of thumb is, if the data
backing the list can *change* while the list is displaying it, then you want
-to use a ContentProvider. While it isn't the only way to get everything working,
-together with Loaders, it's just very smooth. The data is fetched on a
-background thread and is always up to date. And the system does it all
-for you (as long as you have a ContentProvider). What's not to like?
+to use a ContentProvider.
### What's a ContentProvider
A ContentProvider is seperate from the actual data. In this example, and many
@@ -52,16 +20,8 @@ have to be. We will use the Provider to supply our list with content. The advant
over a simple ArrayAdapter will be that if the data changes, the list will change,
all by itself, as it happens.
-### What's a Loader
-Loader is a class offered by the Android Framework. It loads (surprise) data
-in a background thread and offers a callback interface to allow you to
-use that data once it's loaded. We will focus entirely on the case of using
-the Loader together with a database cursor. You can use a Loader to load
-anything in the background though. So if you have data stored as txt files,
-you can use a Loader then as well.
-
### What's SQLite and why do I want to store data in a database
-SQLite is a dialect of SQL, which stands for *Structured Query Language*. There are
+SQLite is a dialect of SQL, which stands for *Simple Query Language*. There are
many dialects of SQL and this is the one supported by Android. It is a light and
fast version of SQL which does not support all features present in other dialects,
but you can do anything even though you might have to phrase it differently.
@@ -74,20 +34,20 @@ searches among *millions* of entries in real time.
I will be using Eclipse together with the standard SDK only. Target will be Jelly Bean MR2
(Android 4.2), but compatibility will be preserved back to Ice Cream Sandwich.
I am assuming that you have managed to install Eclipse together with the SDK and
-are good to go. If not, follow the steps [here](http://developer.android.com/sdk/installing/bundle.html). Make sure you have downloaded
+are good to go. If not, follow the steps here (LINK!). Make sure you have downloaded
the SDK for the Android version you intend to compile against (in our case, android-17).
This is not the same as the least required android version to run your app.
### Create a new project
Go to the menu, select New, Other, Android Application Project.
-
-
+
+
I am going to go
with the MasterDetail style to get a nice two-pane view on tablets for free.
-
+
I selected to name my "items" Persons.
@@ -101,9 +61,7 @@ have a **modern** device, or were smart enough to get the Nexus S back in the da
put your least required version to ICS (android-14). ICS also introduced a lot of great
APIs which you don't want to miss out on. Many of them can be used with the support package
but to get the action bar and good looks from ICS, you'll need some library like
-ActionBarSherlock, and that's a tutorial for another day. The project wizard
-adds the support library by default, so staying backwards compatible shouldn't
-be too hard.
+ActionBarSherlock, and that's a tutorial for another day.
## Let's make our database
By selecting the MasterDetail style in the wizard, we got a lot of code for free.
@@ -119,11 +77,11 @@ first thing we want to do is to replace this with the SQLite database.
First create a new package for your database (not necessary, it's just nice).
I'll name it "com.example.providerexample.database".
-
+
Next, in that package create a new class called "DatabaseHandler".
-
+
Once you
have the class open, make it extend "SQLiteOpenHelper" and save.
@@ -132,26 +90,17 @@ imported. Put the text cursor
somewhere in "SQLiteOpenHelper", hit **CTRL-1**, and select
"import SQLiteOpenHelper.."
-
+
Save. Now, we need to implement the needed methods. Put the text cursor instead
somewhere in "DatabaseHandler", **CTRL-1**, "Add unimplemented methods..".
-
+
The last thing missing is a constructor. Instead of adding a default one, add
the following code to the top of the class:
```java
- private static DatabaseHandler singleton;
-
- public static DatabaseHandler getInstance(final Context context) {
- if (singleton == null) {
- singleton = new DatabaseHandler(context);
- }
- return singleton;
- }
-
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "providerExample";
@@ -159,12 +108,13 @@ the following code to the top of the class:
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
- // Good idea to use process context here
- this.context = context.getApplicationContext();
+ this.context = context;
}
```
-Your project should no longer show any errors.
+Your project should no longer show any errors. This stage of the project
+corresponds to
+commit 22a5b48f963eac813ad67b8f2682b8174ff62652.
Before we make any further changes to the DatabaseHandler, let's make a
Person class. We are now doing a kind of DAO/ORM approach
@@ -321,17 +271,17 @@ do the following: add/update a person, remove a person and of course get a perso
Let's add methods corresponding to those cases:
```java
- public synchronized Person getPerson(final long id) {
+ public Person getPerson(final long id) {
// TODO
return null;
}
- public synchronized boolean putPerson(final Person person) {
+ public boolean putPerson(final Person person) {
// TODO
return false;
}
- public synchronized int removePerson(final Person person) {
+ public int removePerson(final Person person) {
// TODO
return 0;
}
@@ -342,15 +292,13 @@ Your case might differ but I find that if my code wants to save a person,
then it wants to save it regardless if it is already present in the
database or not.
-The methods are *synchronized* because we are going to use loaders to load
-the data, which run on separate background threads. So we want to make sure
-that only one thread is reading/writing at any given time.
+We are now at commit c2a050d32455eb292c1aec35dc49dcf41c69873d.
Let's start with *getPerson*. All we want to do is query the database
for a row with the specified id.
```java
- public synchronized Person getPerson(final long id) {
+ public Person getPerson(final long id) {
final SQLiteDatabase db = this.getReadableDatabase();
final Cursor cursor = db.query(Person.TABLE_NAME,
Person.FIELDS, Person.COL_ID + " IS ?",
@@ -364,7 +312,7 @@ for a row with the specified id.
item = new Person(cursor);
}
cursor.close();
-
+ db.close();
return item;
}
```
@@ -376,12 +324,12 @@ row in the database matches the specified ID. IDs start at 1, so -1 is
always a safe default value. The delete method is similarly simple:
```java
- public synchronized int removePerson(final Person person) {
+ public int removePerson(final Person person) {
final SQLiteDatabase db = this.getWritableDatabase();
final int result = db.delete(Person.TABLE_NAME,
Person.COL_ID + " IS ?",
new String[] { Long.toString(person.id) });
-
+ db.close();
return result;
}
```
@@ -394,7 +342,7 @@ because it is both an insert and an update method.
First, we try to update the person. If that fails, we insert it instead.
```java
- public synchronized boolean putPerson(final Person person) {
+ public boolean putPerson(final Person person) {
boolean success = false;
int result = 0;
final SQLiteDatabase db = this.getWritableDatabase();
@@ -418,12 +366,13 @@ First, we try to update the person. If that fails, we insert it instead.
}
}
+ db.close();
+
return success;
}
```
-Our ORM layer is complete.
-
+Our ORM layer is complete. This is at commit b6a3a519ae45c762b98e43c6a8455147303fa06b.
Using Person as a base, it is fairly easy to add additional tables to the database.
All we need are get,put and remote methods in the database handler and we're set.
Changes made to Person basically never have to touch the database handler ever.
@@ -438,11 +387,11 @@ at first, so making it will be quick. First we need to create the shell of the
class. The newer versions of the Android SDK make this easy. Go to New ->
Other. Then select "Android Object".
-
+
Next select "ContentProvider" from the list!
-
+
It's important to keep in mind what you type as your authority. It should
basically be "your.package.provider", but that's just a convention I read
@@ -450,12 +399,7 @@ somewhere. It would be anything but must be unique to your application.
I went with *com.example.providerexample.provider*. Exported isn't needed
as we will only use the provider internally so far.
-
-
-By default, the wizard places the class in your main package. I want it to
-be in the database package. Remember if you move it, you must change the
-corresponding package name in the *AndroidManifest.xml* or your app will
-crash on start.
+
Now you have the shell of a Provider done! This is the complete generated class:
@@ -621,13 +565,6 @@ And similarly for *removePerson*:
}
```
-Last, make the Provider listen for such notifications. Add the following
-line to both blocks in *query*:
-
-```Java
-result.setNotificationUri(getContext().getContentResolver(), URI_PERSONS);
-```
-
That's it. We're done. Here are the complete *PersonProvider* and *DatabaseHandler* classes before we move on to displaying the content:
```java
@@ -779,8 +716,7 @@ public class PersonProvider extends ContentProvider {
.getReadableDatabase()
.query(Person.TABLE_NAME, Person.FIELDS, null, null, null,
null, null, null);
- result.setNotificationUri(getContext().getContentResolver(), URI_PERSONS);
- } else if (uri.toString().startsWith(PERSON_BASE)) {
+ } else if (uri.toString().startsWith(PERSON_BASE)) {
final long id = Long.parseLong(uri.getLastPathSegment());
result = DatabaseHandler
.getInstance(getContext())
@@ -789,8 +725,7 @@ public class PersonProvider extends ContentProvider {
Person.COL_ID + " IS ?",
new String[] { String.valueOf(id) }, null, null,
null, null);
- result.setNotificationUri(getContext().getContentResolver(), URI_PERSONS);
- } else {
+ } else {
throw new UnsupportedOperationException("Not yet implemented");
}
@@ -885,7 +820,7 @@ with the following to get a more interesting view:
This will look like this:
-
+
The whole thing is wrapped in a scrollview to allow people to have really long
biographies even on small screens.
@@ -939,7 +874,7 @@ the following in it:
Create a new layout xml file called "person_listitem.xml", make the
root view a linear vertical layout.
-
+
You want the file contents to look like:
@@ -989,7 +924,6 @@ You want the file contents to look like:
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
- android:maxLines="3"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:textColor="#ff8d8d8d"
@@ -1008,74 +942,16 @@ its content:
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@id/android:list"
- android:divider="@android:color/transparent"
- android:dividerHeight="12dp"
android:drawSelectorOnTop="true"
- android:background="#e5e5e5"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- />
+ android:background="#e5e5e5" />
```
This is a straight up list view with a grey background and it draws
selectors on top. The items in the list will now look like this:
-
+
-Because of the background, I want to move the location of some margins so the
-correct background is rendered at that location.
-
-*activity_person_twopange* only margins and layout weights changed:
-```XML
-
-
-
-
-
-
-
-
-
-```
-
-And same deal for *activity_person_list*:
-```XML
-
-```
+We are now at commit 1a0b5e10466e1cf0500c698bb95cb2a241ec91bb.
## Make the app use the new layouts and load the data
By now you should have one or two compiler errors because we removed
@@ -1216,25 +1092,6 @@ public class PersonDetailFragment extends Fragment {
}
```
-#### Why not use the provider here?
-It would be good practice to use a Loader to fetch the Person from the Provider,
-if only just because the data would be loaded on a background thread. Right
-now the fragment is fetching the person on the UI thread.
-
-First, I wanted to show how to use an SQLite database without a ContentProvider.
-As you can see, the changes from some kind of ArrayAdapter situation are quite
-minimal in the fragments/activities.
-
-Second, fetching the data on a background thread is just about the only
-benefit we will get from using a Loader in the detail fragment. We **DON'T**
-want the data to auto update in here like we want it to do in the List.
-Because consider if it is possible that the data is changed somewhere else,
-maybe you implement some kind of synchronization service. It would be really
-bad user experience to have your entire item change as you were editing it.
-
-Fetching a single item on the UI thread is fine for now. If you have more
-advanced ideas in mind, yes you should use a Loader.
-
### Fixing list view
First we need to use the layout defined in "fragment_person_list.xml". This is
more or less only because I want a grey background in the list.
@@ -1248,7 +1105,7 @@ Add:
```
Next we set the adapter using a *SimpleCursorAdapter*.
-Initially it has a null cursor. The data is loaded using a *Loader*.
+Initially it has a null cursor. The data is getting loaded using a *Loader*.
So in *onCreate*, change from:
```java
@@ -1304,7 +1161,7 @@ As a last step, update the *onListItemClick* method to utilize the Cursor instea
But, we must also change the callback interface to use a Long instead of
a String to match our database ID and what the Fragment expects.
-
+
Make suitable changes everywhere. In the same file update the dummyCallback:
@@ -1345,399 +1202,3 @@ And in PersonListActivity update *onItemSelected*:
## Add a new button
Running the app now should present an empty list. Not that interesting!
We need to be able to add some items. Just implement a menu item for that:
-
-
-
-```XML
-
-
-```
-
-Inflate the menu and click handler in *PersonListActivity*:
-
-```Java
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.list_activity, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- boolean result = false;
- if (R.id.newPerson == item.getItemId()) {
- result = true;
- // Create a new person.
- Person p = new Person();
- DatabaseHandler.getInstance(this).putPerson(p);
- // Open a new fragment with the new id
- onItemSelected(p.id);
- }
-
- return result;
- }
-```
-
-Change to LongExtras in *PersonListActivity.java*
-```Java
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_person_detail);
-
- // Show the Up button in the action bar.
- getActionBar().setDisplayHomeAsUpEnabled(true);
-
- // savedInstanceState is non-null when there is fragment state
- // saved from previous configurations of this activity
- // (e.g. when rotating the screen from portrait to landscape).
- // In this case, the fragment will automatically be re-added
- // to its container so we don't need to manually add it.
- // For more information, see the Fragments API guide at:
- //
- // http://developer.android.com/guide/components/fragments.html
- //
- if (savedInstanceState == null) {
- // Create the detail fragment and add it to the activity
- // using a fragment transaction.
- Bundle arguments = new Bundle();
- arguments.putLong(PersonDetailFragment.ARG_ITEM_ID,
- getIntent().getLongExtra(PersonDetailFragment.ARG_ITEM_ID, -1));
- PersonDetailFragment fragment = new PersonDetailFragment();
- fragment.setArguments(arguments);
- getSupportFragmentManager().beginTransaction()
- .add(R.id.person_detail_container, fragment)
- .commit();
- }
- }
-```
-
-## Add some data
-Before shipping off your newly created app you might want to add some data to it.
-You can do so by updating the onCreate method of the DatabaseHandler.
-First you create a new person object, populate it with the desired values and
-finally insert it using the insert method of the db object. Eventually it should look like below.
-
-Do note that ideally any predefined data should be loaded from resources
-and not be hardcoded like done here. But doing so is beyond this tutorial.
-
-```java
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL(Person.CREATE_TABLE);
-
- Person person = new Person();
- person.firstname = "Sylvester";
- person.lastname = "Stallone";
- person.bio = "...";
- db.insert(Person.TABLE_NAME, null, person.getContent());
-
- person.firstname = "Danny";
- person.lastname = "DeVito";
- person.bio = "...";
- db.insert(Person.TABLE_NAME, null, person.getContent());
- }
-```
-
-## Final result
-Nexus 7
-
-
-
-Galaxy Nexus List
-
-
-
-Galaxy Nexus Details
-
-
-
-## Explaining the details
-
-Let's clarify a few of the things I skipped over quite fast.
-
-### URIs
-
-A URI is pretty much an address. You are quite familiar with URIs like
-*http://www.google.com*. The URIs which point to information handled by
-ContentProviders always start with *content://* instead of *http://*, but
-you see that the structure is the same. This part is what is called the
-**scheme**. A URI pointing to a file on the SD card would have the scheme:
-*file://*.
-
-The next part of the URI is the **authority**. This identifies which entity
-(in our case, which provider in which app) should handle the request. In the
-example above the authority was *www.google.com*. In the case of content
-providers, the authority typically involves your package name (like
-*com.example.providerexample*) in order to guarantee its uniqueness to your
-provider. Some Google document says its convention to put *.provider* at
-the end. It makes sure the system knows to pass the request along to our
-content provider and not one of the others in the system.
-
-The final part of the URI is the **path**. The google address does not have
-a path. If it looked like: *http://www.google.com/a/folder/img.png* then
-*/a/folder/img.png* would be the path. This is meaningless to the system
-and only relevant to our content provider. We can define anything we
-want here. We use it to differentiate between different requests. For
-example: */persons* used in a query will retrieve a list of all persons.
-*/persons/id* will fetch only a single person with the designated id.
-*/squirrels* won't lead to anything since the provider doesn't know
-what to do with that. But it could. It's all up to the developer.
-
-### SQLite
-
-There are (many) books written about SQL so I'm not even going to try to
-condense everything thing in here. Instead I'll focus on what you have seen
-and what is obviously still missing.
-
-SQLite is merely the language dialect we are using. We are using it because
-it is what Google decided to support natively in Android. The point is
-to create and manage a database. A relational database (there are other kinds)
-stores its information in tables. Each entry corresponds to a row in the
-table, with each kind of information stored in the different columns.
-
-A concrete example:
-
-
-
-
ID
-
name
-
phonenumber
-
-
-
1
-
Bob
-
326346
-
-
-
2
-
Alice
-
326346
-
-
-
-Created by:
-
-```SQL
-CREATE TABLE contact(
- INT ID primary key,
- TEXT name,
- TEXT phonenumber)
-```
-
-This table would store people with their phone numbers and possibly other
-information as well. Now, if you wanted to support more than one phone number
-per person, this structure would break down. There is no way to make a list
-of phone numbers (without doing string parsing) for a single person here. To
-do that, you'd need to take advantage of the *relational* part of the database.
-We'd have to store the phonenumbers in a separate table. For example:
-
-