The Android File System Onboard: Linux Architecture User privileges – Initially quite limited; some directories hidden – Rooting gives users super user.

Slides:



Advertisements
Similar presentations
Google Android Introduction to Mobile Computing. Android is part of the build a better phone process Open Handset Alliance produces Android Comprises.
Advertisements

Programming with Android: Data management
All About Android Introduction to Android 1. Creating a New App “These aren’t the droids we’re looking for.” Obi-wan Kenobi 1. Bring up Eclipse. 2. Click.
Application Fundamentals. See: developer.android.com/guide/developing/building/index.html.
1 Chapter 12 Working With Access 2000 on the Internet.
Chapter 12: ADO.NET and ASP.NET Programming with Microsoft Visual Basic.NET, Second Edition.
A Guide to Oracle9i1 Introduction To Forms Builder Chapter 5.
CONTENT PROVIDER. Content Provider  A content provider makes a specific set of the application's data available to other applications => Share data to.
Data Persistence in Android
Data Storage: Part 1 (Preferences)
SQLite Database. SQLite Public domain database – Advantages Small (about 150 KB) – Used on devices with limited resources Each database contained within.
CSE 486/586, Spring 2013 CSE 486/586 Distributed Systems Content Providers & Services.
© Keren Kalif Intro to Android Development Written by Keren Kalif, Edited by Liron Blecher Contains slides from Google I/O presentation.
ANDROID UI – FRAGMENTS. Fragment  An activity is a container for views  When you have a larger screen device than a phone –like a tablet it can look.
CS378 - Mobile Computing Web - WebView and Web Services.
Software Architecture of Android Yaodong Bi, Ph.D. Department of Computing Sciences University of Scranton.
Favorite Twitter® Searches App Android How to Program © by Pearson Education, Inc. All Rights Reserved.
XP New Perspectives on Browser and Basics Tutorial 1 1 Browser and Basics Tutorial 1.
Cosc 5/4730 Introduction: Threads, Android Activities, and MVC.
Networking: Part 2 (Accessing the Internet). The UI Thread When an application is launched, the system creates a “main” UI thread responsible for handling.
Cosc 5/4730 Android Content Providers and Intents.
Data Storage: Part 4 (Content Providers). Content Providers Content providers allow the sharing of data between applications. Inter-process communication.
COMP 365 Android Development.  Manages access from a central database  Allows multiple applications to access the same data.
This work is licensed under the Creative Commons Attribution 4.0 International License. To view a copy of this license, visit
CS378 - Mobile Computing Intents.
CS378 - Mobile Computing Persistence. Saving State We have already seen saving app state into a Bundle on orientation changes or when an app is killed.
Data Storage: Part 2 (File System). Internal Storage versus External Storage Internal storage − for private data –By default, files saved to the internal.
CSE 486/586, Spring 2012 CSE 486/586 Distributed Systems Recitation.
Chapter 3 Servlet Basics. 1.Recall the Servlet Role 2.Basic Servlet Structure 3.A simple servlet that generates plain text 4.A servlet that generates.
Threads and Services. Background Processes One of the key differences between Android and iPhone is the ability to run things in the background on Android.
CS378 - Mobile Computing Intents. Allow us to use applications and components that are part of Android System – start activities – start services – deliver.
Nilesh Singh Local Data Storage option Android provides several options for you to save persistent application data. - Shared preferences - Creation.
Address Book App 1. Define styles   Specify a background for a TextView – res/drawable/textview_border.xml.
Android – Fragments L. Grewe.
Services A Service is an application component that can perform long-running operations in the background and does not provide a user interface. An application.
CS378 - Mobile Computing Persistence. Saving State We have already seen saving app state into a Bundle on orientation changes or when an app is killed.
Persistence Dr. David Janzen Except as otherwise noted, the content of this presentation is licensed under the Creative Commons Attribution 2.5 License.
Mobile Software Development ISCG 7424 Department of Computing UNITEC John Casey and Richard Rabeder SQLite and Permissions.
Mobile Programming Lecture 7 Dialogs, Menus, and SharedPreferences.
HW#9 Clues CSCI 571 Fall, HW#9 Prototype
Android - SQLite Database 12/10/2015. Introduction SQLite is a opensource SQL database that stores data to a text file on a device. Android comes in with.
SQlite. SQLite is a opensource SQL database that stores data to a text file on a device. Android comes in with built in SQLite database implementation.
© 2016 Cengage Learning®. May not be scanned, copied or duplicated, or posted to a publicly accessible website, in whole or in part. Android Boot Camp.
Lecture 2: Android Concepts
Address Book App 1 Fall 2014 CS7020: Game Design and Development.
CHAPTER 9 File Storage Shared Preferences SQLite.
By: Eliav Menachi.  On Android, all application data (including files) are private to that application  Android provides a standard way for an application.
CMPE419 Mobile Application Development Asst.Prof.Dr.Ahmet Ünveren SPRING Computer Engineering Department Asst.Prof.Dr.Ahmet Ünveren
The Ingredients of Android Applications. A simple application in a process In a classical programming environment, the OS would load the program code.
The Flag Quiz app tests your ability to correctly identify 10 flags from various countries and territories.
Data Storage in Android Димитър Н. Димитров. Why talk about data? Why not 3D graphics or network connectivity? Data as fundamental term in computer science.
Content Providers.
CS371m - Mobile Computing Intents 1. Allow us to use applications and components that are already part of Android System – start activities – start services.
Data Persistence Chapter 9. Objectives Learn about data storage methods Understand use of Shared Preferences Understand file-based storage and the differences.
Making content providers
Android Application -Architecture.
Content provider.
Android Content Providers & SQLite
Lecture 2: Android Concepts
Android Application Data Storage 1.
The Android File System
Mobile Application Development Chapter 5 [Persistent Data in Android]
ANDROID UI – FRAGMENTS UNIT II.
CMPE419 Mobile Application Development
CMPE419 Mobile Application Development
Mobile Computing With Android ACST 4550 Android Database Storage
Android Developer Fundamentals V2
Service Services.
Preference Activity class
CIS 470 Mobile App Development
Presentation transcript:

The Android File System Onboard: Linux Architecture User privileges – Initially quite limited; some directories hidden – Rooting gives users super user access o Procedure is different for different devices o Destroying the operation of the device: bricking Onboard data: Applications have their reserved storage areas (sandbox) External data – SD card or USB connection – Public shared: /mnt/sdcard/ – Writing to external storage has no security protection

Managing Data (Alternatives) Application Direct Access: Read only from res/raw or assets directories Web-based: Interact through web-URLs to access cloud-based data Direct File I/O: Read/write files onboard or on SD cards – Use Standard Java stream and Random Access File classes – Restriction: Onboard file I/O restricted to application sandbox – Restriction: SD card writes requires access permission Preferences: Key/Value pairs of data Database Tables: Use the built-in SQL-Lite database facility Increase functionality: – Content Providers: expose data to other applications – Services: background processes that run detached from any view

Application Direct Access Static application files – Custom codecs that are not widely supported – XML-based configuration data Store either in res/raw or in assets – res/raw enables creating sub-directories for specific device configurations – Files stored either in res/raw or in assets are not pre-compiled by Android – Files stored directly in the application are read-only and cannot be modified – Access using standard Java I/O operations InputStream is = app.getResources().openRawResource(R.raw.foo); in = BufferedReader in = new BufferedReader(new InputStreamReader(is))); InputStream rawRes = context.getAssets().open(“foo.bar"); Reader r = new BufferedReader(new InputStreamReader(rawRes, "UTF8")); Note: Use lower case alphanumerics to name files in res/raw

Downloading Files Downloading quickly degrades battery life Solutions – Pre-fetch: A single large download has less impact than multiple smaller downloads – Reuse existing connections rather than reestablishing them – Schedule regular downloads at the longest intervals that are possible – Bundle non-time sensitive requests together

Download XML from Server String myFeed = getString(R.string.my_feed); // HTTP Web address try {URL url = new URL(myFeed); // Create a new HTTP URL connection URLConnection connection = url.openConnection(); HttpURLConnection httpConnection = (HttpURLConnection)connection; int responseCode = httpConnection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) {InputStream in = httpConnection.getInputStream(); processStream(in); // Use standard Java DOM parsing classes } } catch (MalformedURLException e) { Log.d(TAG, "Malformed URL", e); } catch (IOException e) { Log.d(TAG, "IO Exception.", e); } Requires:

Download Using Download Manager DownloadManager m= (DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE); long myReference = m.enqueue(new Request(Uri.parse(R.string.webLoc))); BroadcastReceiver receiver = new BroadcastReceiver() public void onReceive(Context context, Intent intent) { long reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); if (myReference == reference) {Query query = new Query(); Cursor cursor = downloadManager.query(query.setFilterById(reference)); if (cursor.moveToFirst()) { int fileX = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME); int uriX = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI); String fileName = cursor.getString(fileX), fileUri = cursor.getString(uriX); // TODO Do something with the file. } cursor.close(); } } }; registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) ); Note: The cursor object contains information about downloaded files

Listen for Downloaded Files IntentFilter f = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); registerReceiver(receiver, f); } BroadcastReceiver receiver = new BroadcastReceiver() public void onReceive(Context context, Intent intent) {String id = DownloadManager.EXTRA_DOWNLOAD_ID; long[] references = intent.getLongArrayExtra(id); // Array of downloaded file ids for (long reference : references) {String mime = getMimeTypeForDownloadedFile (reference); { // Handle files that this activity recognizes. } }}} ;

Specifying Download Locations Default Location: A shared download cache with system generated file names Overriding the download location requires: <uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" /> To designate an arbitrary path in external storage Request request = new Request(uri); request.setDestinationUri(Uri.fromFile(f)); To designate a standard external download folder for the application request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, fileName); To designate location which shares with music players request.setDistinationInExternalPublicDir (Environment.DIRECTORY_MUSIC, fileName); Note: We cannot download to internal storage using DownloadManager

SD Card File IO SD Card path: getExternalStorageDirectory() How: Use standard Java File I/O Notes: – Manifest: "android.permission.WRITE_EXTERNAL_STORAGE" – Application manifests can set preference to SD Card installation – Check SD Availability in Java: Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) Convention: write to /Android/data/ /files/ Example File sdCard = Environment.getExternalStorageDirectory(); File dir = new File (sdcard.getAbsolutePath() + " /Android/data/ /files/ "); dir.mkdirs(); // Make directories with missing parents. File file = new File(dir, "filename"); // Instantiate a file object FileOutputStream f = new FileOutputStream(file); // Open for writing

Writing to Internal Storage Writing to internal storage – Each application has a designated directory to which to write files – There is a maximum storage amount, varying per device – Flags exist to control inter-application access MODE_PRIVATE - No access for other applications MODE_WORLD_READABLE - Read access for other applications MODE_WORLD_WRITABLE - Write access for other applications MODE_WORLD_READABLE | MODE_WORLD_WRITABLE - Read / Write access Open file for writing new BufferedWriter( new OutputStreamWriter( openFileOutput(fileName, MODE_PRIVATE)));

Onboard File I/O Write to a designated place for each application – Where: /data/data/package/files/ using onboard storage – How: Use standard java.io classes, with relative, not absolute, paths – Applications can: o Write into its application directory o Create subdirectories o Give read/write permissions to other applications (MODE_PRIVATE, MODE_WORLD_READABLE | MODE_WORLD_WRITABLE) Android Helper classes in the Context object – getDir(String fileName, int permissions): Creates or access directory – getFilesDir(): Get absolute path to application directory – getCacheDir(): Get non-permanent temporary storage directory – openFileInput(String fileName): Open a file for input – openFileOutput(String fileName, int permissions): Create a new file Note: There is also a sharedPreferences directory for preferences, a databases directory for SQLite tables, and a cache directory

Copy File from Server public void DownloadFile(String fileURL, String fileName) { try { HttpURLConnection c = (HttpURLConnection) fileURL.openConnection(); c.setRequestMethod("GET"); c.setDoOutput(false); // Tru for “POST” with intent to send to server c.connect();// Establish connection with server InputStream in = c.getInputStream(); // Ready to read File root = Environment.getExternalFilesDir(null); // Application area // Prepare output stream FileOutputStream out = new FileOutputStream(new File(root, fileName)); byte[] buffer = new byte[1024]; int len = 0; // Note the buffer overflow possibility while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } // Write block f.close(); }} }catch (Exception e) { Log.d("Downloader", e.getMessage()); }

Preferences Initial Purpose: – Persistent storage for user options – Analogous to cookies in Web-based applications More General Purpose: – Maintains the application state across terminations and restarts – Provides mechanism for applications to persistently store additional data without using SQL or Files Preferences Framework 1.Define preferences 2.Display settings 3.Persist user selections

Accessing Shared Preference Data // getPreferences is a method in the Activity class SharedPreferences prefs = getPreferences(Activity.MODE_PRIVATE); int intValue = getInt("IntKey", 22); long longValue = getLong("LongKey", 0); String name = getString("NameKey", ""); int floatValue = getFloat("FloatKey", 0.0); int booleanValue = getBoolean("BoolKey", false); Set set = getStringSet("SetKey", 22); Map keysAndValues = getAll(); Notes: 1.The second argument is the default if the key was not previously stored 2.There is no getDouble() method

Modifying SharedPreference Data SharedPreferences preferences = getPreferences(Activity.MODE_PRIVATE); // or getSharedPreferences("fileName"); SharedPreferences.Editor editor = preferences.edit(); editor.putInt("IntKey", 22); editor.putLong("LongKey", 0); editor.putString("NameKey", ""); editor.putFloat("FloatKey", 0.0); editor.putBoolean("BoolKey", false); editor.commit(); Notes: 1.puts can be chained: editor.putInt(“intKey”, 22).putLong(“LongKey”, 0); 2.editor.apply() works asynchronously, editor.commit() is synchronous 3.editor.clear() erases all of the preference keys 4.editor.remove(“Key”) deletes a preference 5.Shared preferences use a file name for multi-activity sharing

Preference Views Preference Screen  The view on the left  View on the right appears When the user clicks after preference screen clicked Selection Screen  Modal Dialog on the right  Saves selection and disappears after a user selection

Step 1: Defining Preferences <PreferenceScreen xmlns:android=" android:key="flight_option_preference" <ListPreference /> public class FlightPreferenceActivity extends PreferenceActivity protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.flightoptions);} XML Listing (in res/xml) for the preferences shown on the previous screen

Define Strings in res/values Preferences Demo My Preferences Set Search Options Flight Options Set Search Options Total Cost # of Stops Airline Choose Flight Options 1 Selected Sort Option Settings Quit

Manifest <manifest xmlns:android=" package="com.syh" android:versionCode="1" android:versionName="1.0">

Define Main Android Activity // This is public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.main); // Assuming there is a TextView layout tv = (TextView)findViewById(R.id.text1); setOptionText(); // Helper method to get user preference and adjust view public boolean onCreateOptionsMenu(Menu menu) {MenuInflater inflater = getMenuInflater(); // Inflate main menu XML with link to preference option inflater.inflate(R.menu.mainmenu, menu); return true; // Menu is now active }

Main Activity Selection public boolean onOptionsItemSelected (MenuItem item) {if (item.getItemId() == R.id.menu_prefs) {Intent intent = new Intent().setClass(this, com.syh.PreferenceActivity.class); this.startActivityForResult(intent, 0); // Second parameter is for a switch in listener } else if (item.getItemId() == R.id.menu_quit) { finish(); } return true;// Start preference menu when its item is selected public void onActivityResult(int reqCode, int resCode, Intent data) { super.onActivityResult(reqCode, resCode, data); SharedPreferences prefs = getDefaultSHaredPreferences(this); String key = this.getResources().getString(R.string.SelectedSortOption); String default = this.getResources().getString(R.string.SortDefaultValue); String selection = prefs.getString(key, default); String[] optionText = this.getResources().getStringArray(R.string.FlightSortOptions); tv.setText("option = " + pref + " (" +optionText[Integer.parseInt(pref)] + ")"); }

CheckBoxPreference (/res/xml/chkbox.xml) <PreferenceScreen xmlns:android =" android:key="flight_columns_pref"> <CheckBoxPreference android:key="show_airline_column_pref" android:title="Airline" android:summary="Show Airline column" /> <CheckBoxPreference android:key="show_departure_column_pref" android:title="Departure" android:summary="Show Departure column" /> <CheckBoxPreference android:key="show_arrival_column_pref" android:title="Arrival" android:summary="Show Arrival column" /> <CheckBoxPreference android:key="show_total_travel_time_column_pref" android:title="Total Travel Time"android:summary="Show Total Travel Time column" /> <CheckBoxPreference android:key="show_price_column_pref" android:title="Price" android:summary="Show Price column" /> Note: For Radio Buttons, use the List Preference

Using Check Box Preferences // CheckBoxPreferenceActivity.java import android.os.Bundle; import android.preference.PreferenceActivity; public class CheckBoxPreferenceActivity extends PreferenceActivity protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.chkbox); } // Access preference in an activity SharedPreferences prefs = getSharedPreferences("fileName"); Boolean option = prefs.getBoolean("show_price_column_pref", false);

EditTextPreference <PreferenceScreen xmlns:android= android:title=“Set Package Name" android:summary="Set the package name for generated code"> <EditTextPreference android:key="package_name_preference" android:title="Set Package Name" android:dialogTitle="Package Name" android:summary="Set the package name for generated code" />

Categories of Preferences <PreferenceScreen xmlns:android=" android:key="using_categories_in_root_screen" android:title="Categories" android:summary="Using Preference Categories"> <PreferenceCategory xmlns:android= android:key="meats_category" android:title="Meats" android:summary="Meat preferences"> <CheckBoxPreference android:key="fish_selection_pref" android:title="Fish" android:summary="Fish is great for the healthy" /> <CheckBoxPreference android:key="chicken_selection_pref" android:title="Chicken" android:summary="A common type of poultry" /> <CheckBoxPreference android:key="lamb_selection_pref" android:title="Lamb" android:summary="Lamb is a young sheep" /> <PreferenceCategory xmlns:android= android:key="vegi_category" android:title="Vegetables" android:summary="Vegetable preferences"> <CheckBoxPreference android:key="tomato_selection_pref" android:title="Tomato " android:summary="It's actually a fruit" /> <CheckBoxPreference android:key="potato_selection_pref" android:title="Potato" android:summary="My favorite vegetable" /> Purpose: Provide titles to groups of similar preferences

Preference Fragments Android versions 3.0 and newer recommend using fragments for preferences instead of activities Check Android Version: if (Build.VERSION.SKK_INT<Build.VERSION_CODES.HONEYCOME) {/* Use preference activity approach */ } else{ /* Use preference fragment approach */ } Implementation Steps 1.Define preference screens in XML (as shown on previous slides) 2.Add PreferenceFragment to the activity using the FragmentManager 3.Create the PreferenceFragment class

Preference Fragment in an Activity public class PreferenceFragmentActivity extends Activity public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentManager manager = getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); MyFragment fragment = new MyFragment(); trans.replace(android.R.id.content, fragment1); trans.addToBackStack(null); trans.commit(); } } Note: Don’t add the fragment to the application manifest

Preference Fragment Class public class MyFragment extends PreferenceFragment public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // configure the preferences from an XML file addPreferencesFromResource(R.xml.preferences); PreferenceManager manager = getPreferenceManager(); SharedPreferences shared = manager.getSharedPreferences(); shared.registerOnSharedPreferenceChangeListener(this); } onSharedPreferenceChanged(SharedPreferences pref, String key) { /* Handle preference change here */} }

SQLite Android SQLite: – Lightweight database system – Standards-compliant – Single Tier (no server involved) – Open source Standard SQL queries “SELECT ID, CITY, STATE FROM STATION WHERE LAT_N > 39.7;” Application content providers provide – Standard interface to SQL tables to other applications – For application private tables, content providers are not needed

Authorities / URI Definition: An authority is a registered name on an android device (ex: Content Provider name. Authorities must be unique on the system. Registration: Accomplished in an application manifest Syntax: com.company.someProvider Examples: org.acorns.LessonProvider or com.android.provider.BookProvider Analogy: Authorities are to Android what domain names are to the Web Activity access using URIs – Syntax: content://authority-name/path-segment/path-segment/… – Access book table: content://com.anroidbook.provider.BookProvider/books – Access particular book: content://com.anroidbook.provider.BookProvider/books/12 Activity Interface: Through Content Providers, which fill in abstract methods Purpose: Publish application SQL tables and data for external activity access

MIME Types Definition: Industry standard way to indicate a particular data format Syntax: Two text strings separated by slashes First part (category): application, audio, image, text, video, etc Second Part (codec): html, css, xml, pdf, rtf, etc. Examples: text/htm, application/pdf, image/jpeg, audio/mpeg, etc. Android MIME Types (Similar syntax as standard MIME types) – First Part o Access single items: vnd.android.cursor.item o Access multiple items: vnd.android.cursor.dir – Second Part: vnd.yourCompany.type – Examples: vnd.android.cursor.dir/vnd.google.note or vnd.android.cursor.item/vnd.google.note Purpose: Indicate a type of data that a content provider deals with

Content Provider Framework An application registers its content provider using its manifest The code for the content provider is written An application request data using the published MIME type Android looks through the registered manifests for an appropriate provider The provider activity is launched to manipulate or return data If more than one provider exists, the user selects the one to use Android Built-in content providers: content://media/internal/images/, content://media/external/images/, content://contacts/people/

Content Providers Register an authority using the AndroidManifest.xml file – Definition: An authority is a registered name – Analogy: authority is to an Android device what a domain name is to the Internet Syntax: ( Using a package name minimizes redundancies on a system) Example: Another application example: A well-defined interface to data for application access

MIME Types Specifies the data type an activity can process – Register in the AndroidManifest.xml file – Example: "vnd.android.cursor.dir/vnd.google.note" OR "vnd.android.cursor.dir/vnd.google.note" Sample Syntax: vnd.android.cursor. /vnd.company.type – vnd: non-standard type (vendor) – android.cursor: required for ContentProvider Manifest registrations – item: single record; dir: collection of records – google: company name – note: content type AndroidManifest.xml registration Acronym: Multipurpose Internet Mail Extension

Referring to a Content Provider URI and URL – Uniform resource identifier (URI) Identifies the name of a resource, but not necessarily information regarding its location – Uniform resource Location (URL) is a URI, that identifies a resource location – Text usage: URI for content providers; URL for referring to Web locations URI of a content provider content://com.company.fooProvider/ content://com.acorns.provider.Lessons/ content://com.google.provider.NotePad/ Note: Android provided shortcut URIs: contacts for com.google.android.contacts Refer to the notes SQLite notes table content://com.google.provider.NotePad/notes/ Refer to the tenth note content://com.google.provider/NotePad/notes/10

Register the Provider <provider android:name="NotePadProvider" android:authorities="com.google.provider.NotePad" />

Implement the Provider Plan the Database Extend the ContentProvider class Fill in a variety of methods to be overloaded – onCreate(): When the database is created – onUpgrade(): When the database layout changes – getType(): Return the MIME data type – query(): Handle queries to the data – insert(), delete(), and update() methods

A Managed Query in Content Provider // Specify needed columns string[] projection = new string[] { People._ID, People.NAME, People.NUMBER }; // Specivy URI using static Contacts constants Uri contactUri = Contacts.People.CONTENT_URI; // Invoke a content provider query Cursor cursor = managedQuery( contactUri, projection, //Which columns to return null, null, // Selection and WHERE clauses Contacts.People.NAME + " ASC"); // Order-by (ascending by name) Purpose: Query SQL lite table for relevant data (cursor) Definition: An Android cursor is a collection of rows of data Other classes exist (ex: SQLiteQueryBuilder) for using standard SQL strings

Navigating through a cursor Manipulate the cursor (row pointer) – if (cursor.moveToFirst() == false) – cursor.isBeforeFirst(), cursor.isAfterLast, cursor.isClosed() – while (cursor.moveToNext()) { /* code here */ } – for (cursor.moveToFirst(); !cursor.isAfterLast(); cur.moveToNext) { … } Get column numbers from names – int nameColumn = cursor.getColumnIndex(People.NAME); – int phoneColumn = cursor.getColumnIndex(People.NUMBER); Get Data from column – String name = cursor.getString(nameColumn); – String number = cursor.getString(phoneColumn); Prerequisites: Know column names, data types, column name to index relationship After a query, the cursor points before the first; use moveToFirst(); use moveToNext() for the initial access

Other Access Methods Add ContentValues values = new ContentValues(); values.put(BookProviderMetaData.BookTableMetaData.BOOK_NAME, "book1"); values.put(BookProviderMetaData.BookTableMetaData.BOOK_AUTHOR, "author-1"); ContentResolver resolve = context.getContentResolver(); URI uri = BookProviderMetaData.BookTableMetaData.CONTENT.URI; Uri inserted = resolve.insert(uri, values); Delete: Assume that bookIndex is pre-defined ContentResolver resolve = context.getContentResolver(); URI uri = BookProviderMetaData.BookTableMetaData.CONTENT.URI; Uri delURI = uri.withAppendedPath(uri, Integer.toString(bookIndex)); resolve.delete(delUri, null, null); Count URI uri = BookProviderMetaData.BookTableMetaData.CONTENT.URI; Cursor cursor = activity.managedQuery(uri, null, null, null, null); Int numberOfRecords = cursor.getCount(); cursor.close(); See next slide for symbolic constant definitions

BookProviderMetaData class

Content Resolver Definition: A Content Resolver is an Android class that matches the URI to an available Content Provider that can handle the data Purpose: Separate the provider from the data, enabling the possibility of multiple content providers available to handle the same data types Access: Use a collection of method calls to insert, retrieve, delete, update data records Example: (insert a new note into the notepad) ContentResolver resolver = activity.getContentResolver(); Uri newUri = resolver.insert(Notepad.Notes.CONTENT_URI, values); Note: values is an instance of the ContentValues class

Store Files in an SQLite Database Steps 1.Create the SQLite table with a column called _data 2.Get a writeable output stream 3.Write the file to the reserved column name _data I/O Example //Use a content resolver to insert the record ContentResolver contentResolver = activity.getContentResolver(); Uri newUri = contentResolver.insert(Notepad.Notes.CONTENT_URI, values); //Use the content resolver to get an output stream directly OutputStream outStream = contentResolver().openOutputStream(newUri); writeFileToRecord(outStream); outStream.close(); ContentValues object contains a set of values Note: The data is actually stored in a separate area. The _data column contains the Uri reference to the data

DataBase Helper Purpose – Manage database creation and version management – Responsible for creating and upgrading an SQLite database – Defer database opening and updating to the first use – Avoids blocking application startup with compute intensive database upgrades – Contains methods for getWritableDatabase and getReadableDatabase – Simplifies Content Provider access to files – Eliminates concern over whether the application was terminated Implementation – Create a class that extends SQLiteOpenHelper – Override onCreate() and onUpgrade() methods

Helper Code (Two tables: Employees, Department) public class DatabaseHelper extends SQLiteOpenHelper { static final String dbName="demoDB"; static final String employees="Employees"; static final String colID="EmployeeID"; static final String colName="EmployeeName"; static final String colAge="Age"; static final String colDept="Dept"; static final String depts="Department"; static final String colDeptID="DeptID"; static final String colDeptName="DeptName"; static final String viewEmps="ViewEmps"; public DatabaseHelper(Context context) // Constructor { super(context, dbName, null /* Extension to cursor class */, 1 /* version */); } This application will need to override onCreate and onUpgrade

Helper Example (cont.) public void onCreate(SQLiteDatabase db) {db.execSQL("CREATE TABLE " + "depts + " (" + colDeptID +" INTEGER PRIMARY KEY, " +colDeptName+ " TEXT)"); db.execSQL("CREATE TABLE "+employees + " ("+ colID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + colName + " TEXT, "+ colAge + " Integer, " + colDept + " INTEGER NOT NULL, FOREIGN KEY ("+ colDept +") REFERENCES " + deptTable+" ("+colDeptID+"));"); db.execSQL("CREATE TRIGGER fk_empdept_deptid "+" BEFORE INSERT ON "+employees+ " FOR EACH ROW BEGIN" + " SELECT CASE WHEN ( (SELECT " + colDeptID + " FROM " + depts + " WHERE " + colDeptID + "=new." + colDept + " ) IS NULL)" + " THEN RAISE (ABORT, 'Foreign Key Violation') END;" + " END;"); db.execSQL("CREATE VIEW "+ viewEmps + " AS SELECT " + employees + "." + colID + " AS _id," + " " + employees + "." + colName + ", " + employees + "." + colAge + ", " + depts + "." + colDeptName + "" + " FROM "+ employees + " JOIN " + depts + " ON " + employees +"." + colDept+" =" + depts + "." + colDeptID ); }

Helper Example (cont.) Upgrading the DB public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS "+employees); db.execSQL("DROP TABLE IF EXISTS "+depts); db.execSQL("DROP TRIGGER IF EXISTS dept_id_trigger"); db.execSQL("DROP TRIGGER IF EXISTS dept_id_trigger22"); db.execSQL("DROP TRIGGER IF EXISTS fk_empdept_deptid"); db.execSQL("DROP VIEW IF EXISTS "+viewEmps); onCreate(db); } Called when the version number in the constructor changes Note: The activity can respond to menu selections to insert, remove, and update rows

Using a Database helper Helper = new Helper(context, Helper.DATABASE_NAME, null, Helper.VERSION); SQLiteDatabase db = Helper.getWritableDatabase(); // Perform query Cursor cursor = db.query(Helper.DATABASE_TABLE, result_columns, where, whereArgs, group, having, order); SQLiteDatabase db = hoardDBOpenHelper.getWritableDatabase(); // Insert row db.insert(HoardDBOpenHelper.DATABASE_TABLE, null, newValues); SQLiteDatabase db = hoardDBOpenHelper.getWritableDatabase(); // Update row db.update(Helper.DATABASE_TABLE, newValues, where, whereArgs); SQLiteDatabase db = Helper.getWritableDatabase(); // Delete matching rows db.delete(Helper.DATABASE_TABLE, where, whereArgs);

Find media titles and albums String[] projection = { MediaStore.Audio.AudioColumns.ALBUM, MediaStore.Audio.AudioColumns.TITLE }; Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; Cursor cursor = getContentResolver().query(uri, projection, null, null, null); int aX= cursor.getColumnIndexOrThrow(MediaStore.Audio.AudioColumns.ALBUM); int tX = cursor.getColumnIndexOrThrow(MediaStore.Audio.AudioColumns.TITLE); String[] result = new String[cursor.getCount()]; while (cursor.moveToNext()) {String title = cursor.getString(tX), album = cursor.getString(aX); result[cursor.getPosition()] = title + " (" + album + ")"; } cursor.close(); Using the Android provided Media Store Content Provider Other Native Content Providers: Browser, Contacts, Calendar, Call log

Accessing the Contact List int iDCol = ContactsContract.Contacts.ID; int nameCol = ContactsContract.Contacts.DISPLAY_NAME; Uri uri = ContactsContract.Contacts.CONTENT_URI; String[] projection = { iDCol, nameCol }; Cursor cursor = getContentResolver().query(uri, projection, null, null, null); int nameIndex = cursor.getColumnIndexOrThrow(nameCol); int idIndex = cursor.getColumnIndexOrThrow(contactIDCol); String[] result = new String[cursor.getCount()]; while(cursor.moveToNext()) {String name = cursor.getString(nameIndex); String id = cursor.getString(idIndex); result[cursor.getPosition()] = name + " (" + id + ")"; } cursor.close();

Searchable Applications Expose the application to search-facilities Alternatives – Search bar appearing after hardware search button pressed or a program method call – Search widget placed somewhere on the application view – Quick Search implemented as a home screen widget – Enable voice search

Making an Application Searchable In the manifest – Create an xml file with the searchable attributes – Mark the application searchable – Define the intent for the activity processing searches Either create a search activity – Launch when the search is initiated – Process and display the results Or use a search dialog (floating search box) – Hidden by default, but can be initiated by calling onSearchRequested(), which is an Activity class method – If the device doesn’t contain a dedicated search button, add a menu option or widget that calls onSearchRequested() Or use the SearchView widget

Searchable configuration in res/xml <searchable xmlns:android= > The label (required attribute) becomes visible when search is launched and contains the search application name The hint appears in the search box before users enter a query. It contains a hint about what can be searched Other attributes are for search suggestions and voice search Filename: searchable.xml

Searchable launch in Manifest … <activity android:name=".SearchActivity“ android:launchMode="singleTop"> <meta-dataandroid:name="android.app.searchable" /> Note: singleTop prevents multiple instances on the back stack

Search public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search); // Get the intent, verify the action and get the query Intent intent = getIntent(); if (Intent.ACTION_SEARCH.equals(intent.getAction())) {String query = intent.getStringExtra(SearchManager.QUERY); doMySearch(query); // Process the request}

Services Services handle background events separate from a View Services reside in the main thread of the launching process! Use thread facilities to avoid blocking the main thread Only foreground activities have a higher priority, so services are rarely terminated by the OS Proper Handling – Main activity makes requests – Service starts worker threads to perform requests – Bind services to the main thread – Callbacks to the main activity completes transactions. Downloading Threads (maybe thread pool?) Main Activity Service onButtonClick() method gets control in the executing activity Activity uses an intent to request the download from the Service!) Worker Thread (downloading) New worker thread Done downloading!Start new worker thread User selects item to download

Creating a Service 1.Create a class extending the service class 2.Register the service in the application manifest <service android:enabled="true" android:name=".MyService" android:permission="foo.bar.MY_SERVICE_PERMISSION"/> 4.Start and stop of the service in the main activity 5.Use separate threads for compute-bound operations – Bind service to the main activities so the main activity can call service class methods and then update its user interface views 6.Self-terminate the service when it is no longer needed

Starting and Stopping Services Explicitly start My Service Intent intent = new Intent(this, MyService.class); // TODO Add extras if required. startService(intent); } Implicitly start a music Service Intent intent = new Intent(MyMusicService.PLAY_ALBUM); intent.putExtra(MyMusicService.ALBUM_NAME_EXTRA, "United"); intent.putExtra(MyMusicService.ARTIST_NAME_EXTRA, "Pheonix"); startService(intent); Explicitly stop My Service : stopService(new Intent(this, MyService.class)); Implicitly stop Music Service stopService(new Intent(MyMusicService.PLAY_ALBUM));

Creating a Bindable Service public class LocalService extends Service { private final IBinder binder = new LocalBinder(); public class LocalBinder extends Binder { LocalService getService() { return LocalService.this; } public void onCreate() { // TODO: Actions to perform when service is created. } // Return instance after activity call onBindService() public IBinder onBind(Intent intent) { return binder; } /** method for clients */ public int getRandomNumber() { return Math.random(); } } Purpose: Enable activities to access service methods

public class BindingActivity extends Activity // An Activity using a Bound Service { LocalService service; boolean bound = false; private ServiceConnection connection = new ServiceConnection() // Anonymous instance public void onServiceConnected(ComponentName name, IBinder service) { LocalBinder binder=(LocalBinder) service; service=binder.getService();bound=true; public void onServiceDisconnected(ComponentName arg0) {bound = false; } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); protected void onStart() {super.onStart(); Intent intent = new Intent(this, LocalService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); protected void onStop() `{super.onStop(); if (bound) { unbindService(connection); bound = false; } } public void onButtonClick(View v) { if (bound) { int num = service.getRandomNumber(); Toast.makeText(this, "number: "+num, Toast.LENGTH_SHORT).show(); } } }

Updating the GUI from a Service 1.The activity registers a listening object with the service 2.The service broadcasts an intent and the activity responds 3.Use a Handler in an activity private final Handler handler = new Handler(); // Process queue of runnables private OnClickListener buttonListener = new OnClickListener() {public void onClick(View v) {new Thread(new Runnable() { pubic void run() {//.... hard work in separate thread handler.post(new Runnable() { public void run() { //... update the UI } }); }).start(); } }; } Note: There are other possibilities. For example, one could use AsyncTask, IntentService or Loader objects