Android in Action (part III)

Preview:

Citation preview

Android in Action (part III)

Alexey Golubev, Dmitry Lukashev

What is the plan?

Part I Part II Part III

Android UI

Layouts, ListView,

Menu, Dialog, Widgets, Tips & tricks, etc.

Android in Action

Screen rotation, Memory analyze, AIDL, SAX, Debug,

Wakelock, etc.

Java +Android (basics)

JVM, GC, Threads, SDK, NDK, Activity,

Code style, etc.

Agenda

• Debugging hints and tools

• Dealing with screen orientation

• Memory leaks analysis

• Working with Services

• Databases

• XML parsers

• Input methods, Search providers

• Battery life, wakelocks

• Flurry

• Publishing to Android Market

Agenda

• Debugging hints and tools

• Dealing with screen orientation

• Memory leaks analysis

• Working with Services

• Databases

• XML parsers

• Input methods, Search providers

• Battery life, wakelocks

• Flurry

• Publishing to Android Market

Debugging tools

• Android Debug Bridge (ADB)

• Dalvik Debug Monitor Server (DDMS)

• Traceview

• logcat

• ADT plug-in

• DevTools

• SpareParts

• AXMLPrinter2

ADB

• Install/Uninstall apps, port forwarding, scripting, files management

• Shell

• adb shell ls /system/bin

• adb kill-server

$ adb -s emulator-5554 shell # sqlite3 /data/data/com.example.google.rss.rssexample/databases/rssitems.db SQLite version 3.3.12 Enter ".help" for instructions .... enter commands, then quit... sqlite> .exit

Monkey

• Stress-test your application: generate pseudo-random streams of user events such as clicks, touches, or gestures, as well as a number of system-level events

• You can write your own script and execute thru telnet

• You can even take screenshots thru command line

$ adb shell monkey -p your.package.name -v 500

press DPAD_CENTER

sleep 4000

tap 290 40

sleep 1000

tap 290 40

sleep 500

Monkey Demo

logcat

The priority is one of the following character values, ordered from lowest to highest priority:

V — Verbose (lowest priority)

D — Debug

I — Info

W — Warning

E — Error

F — Fatal

S — Silent (highest priority, on which nothing is ever printed)

adb logcat -b radio

DDMS

• Threads info

• VM Heap info

• Allocation Tracker

• System info

• Emulator control

• Screen capture

• File Explorer

Demo

Performance Analysis: Traceview

• In code: – Debug.startMethodTracing(“path”) // at /sdcard

– Debug.stopMethodTracing()

• Using adb: – adb shell am profile com.gtug.project start /sdcard/filename

– adb shell am profile com.gtug.project stop

• Impact performance! <!– AndroidManifest.xml //-->

<application

android:debuggable="true" ... />

Dev Tools

• Account Tester

• Development Setting – Immediately destroy activities (test

onSaveInstanceState())

– Screen updates

– Running processes

• Package Browser

• SyncTester

adb -e pull /system/app/Development.apk ./Development.apk adb -d install Development.apk

Spare Parts

• Battery history

• Usage statistics

AXMLPrinter2

• Converts Android binary XML to human-readable XML http://code.google.com/p/android4me/downloads/list

java -jar AXMLPrinter2.jar AndroidManifest.xml >> 1.txt

€ Д t 4 @ N Z x Љ в ж ш , 6 P d | љ Є в ц : v e r s i o n C o d e v e r s i o n N a m e i c o n l a b e l n a m e m i n S d k V e r s i o n a n d r o i d * h t t p : / / s c h e m a s . a n d r o i d . c o m / a p k / r e s / a n d r o i d p a c k a g e m a n i f e s t c o m . y o t a . m e r g e 1 . 0 a p p l i c a t i o n a c t i v i t y . M e r g e T e s t i n t e n t - f i l t e r a c t i o n a n d r o i d . i n t e n t . a c t i o n . M A I N c a t e g o r y a n d r o i d . i n t e n t . c a t e g o r y . L A U N C H E R u s e s - s d k Ђ яяяя ` яяяяяяяя яяяя яяяя L яяяяяяяя

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.gtug.merge"> <application android:label="@7F040001" android:icon="@7F020000"> <activity android:label="@7F040001" android:name=".MergeTest"> <intent-filter> <action android:name="android.intent.action.MAIN"> </action> <category android:name="android.intent.category.LAUNCHER"> </category> …

Agenda

• Debugging hints and tools

• Dealing with screen orientation

• Memory leaks analysis

• Working with Services

• Databases

• XML parsers

• Input methods, Search providers

• Battery life, wakelocks

• Flurry

• Publishing to Android Market

Screen Orientation: Default Behavior - Recreate

Start

Stop

onCreate(Bundle) onStart()

onResume()

onRestart()

onDestroy()

onPause()

onStop()

Kill process

Running

partly visible

foreground

no longer visible

foreground

onSaveInstanceState(Bundle)

Object onRetainNonConfigurationInstance()

Screen Orientation: Dealing with recreate

• Saving state variables:

– onSaveInstanceState(Bundle)

– onRestoreInstanceState( Bundle)

• Saving Activity data

– Object onRetainNonConfigurationInstance()

– Object getLastNonConfigurationInstance()

Never save UI-dependent objects (even Adapters) using onRetainNonCofigurationInstance()!

Screen Orientation: Custom Behavior

• onConfigurationChanged(Configuration)

• android.view. OrientationEventListener

• setContentView()

<activity

android:configChanges=["mcc", "mnc",

"locale", "touchscreen", "keyboard",

"keyboardHidden", "navigation",

"orientation", "fontScale"]

android:screenOrientation=["unspecified" |

"user" | "behind" | "landscape" |

"portrait" | "sensor" | "nosensor"]

...</activity>

Agenda

• Debugging hints and tools

• Dealing with screen orientation

• Memory leaks analysis

• Working with Services

• Databases

• XML parsers

• Input methods, Search providers

• Battery life, wakelocks

• Flurry

• Publishing to Android Market

Screen Orientation – The Fastest Way to Memory Leak

• References to Activity/Service/Context – Avoid final, static and long-live references – Use Application Context where possible

• References to View, Drawable, Handlers – Any kind of View from findViewById stores whole ViewRoot – Drawable callbacks

• Register/unregister BroadcastReceivers • Bind/unbind from Service

– ServiceConnection – AIDL Callbacks, RemoteCallbackList

• Inner classes – Anonymous inner classes as class fields (ClickListeners)

• Google issue #2423 (http://code.google.com/p/android/issues/detail?id=2423)

Memory Leaks demo

Memory Leaks Analysis: Debug Class

• Activity.getInstanceCount()

• Debug

– Binder transactions, dead objects, etc.

– Number of loaded classes

– setAllocationLimit(int)

– start/stopAllocationCounting()

• Debug.getMemoryInfo(MemoryInfo)

– Dalvik dirty pages

– Native dirty pages

– Other dirty pages

SysInfo -> Memory Usage

Memory Leaks Analysis: DDMS

• Stand-alone DDMS in <android-sdk>/tools – NB: Only one DDMS instance should be launched – Eclipse or stand-alone

VM Heap

Allocation Tracker

Memory Leaks Analysis: MAT

• Stand-alone Memory Analyzer (MAT)

– http://www.eclipse.org/mat/

• Get memory dump using adb shell

$ adb shell chmod 777 /data/misc $ adb shell ps $ adb shell kill -10 [pid] $ adb pull /data/misc/heap-dump-tmXXX-pidXXX.hprof name.hprof

• Convert hprof to Sun format

• Open new hprof dump in stand-alone Eclipse MAT

$ <android-sdk>/tools/hprof-conv name.hprof name4mat.hprof

Memory Analyzer demo

Agenda

• Debugging hints and tools

• Dealing with screen orientation

• Memory leaks analysis

• Working with Services

• Databases

• XML parsers

• Input methods, Search providers

• Battery life, wakelocks

• Flurry

• Publishing to Android Market

Interactions with Android Service

• Context.start/stopService(Intent)

– stopSelf()

• Context.bind/unbindService()

– Interaction AIDL interface

• Permissions

– checkCallingPermission(String)

<service

android:exported=["true", "false"]

android:permission="string"

android:process="name".../>

Android Service Lifecycle

Started by startService()

Shut

down

onStart()

onDestroy()

Kill process

Running

onCreate()

stopSelf() or no

callback

onLowMemory()

Started by bindService()

onBind()

Running with

interactions

onUnbind()

onRebind()

Android Service Lifecycle Extras (SDK 5)

• onStartCommand() – Set:

• START_FLAG_REDELIVERED

• START_FLAG_RETRY

– Return: • START_STICKY_COMPATIBILITY

• START_STICKY

• START_NOT_STICKY

• START_REDELIVER_INTENT

• START_CONTINUATION_MASK

• start/stopForeground() – With Notification

Since platform 2.0!

Android IPC, RPC & AIDL

• IPC – InterProcess Communication

• RPC – Remote Procedure Calls

• AIDL – Android Interface Definition Language

Used locally (by clients of the Service)

Used remotely (by the Service)

Interface generated by the AIDL tool

Defined by the application

Defined by Android

IBinder interface

Binder class

Stub inner class

inner class used by Android

Class that implements the interface

AIDL definition

Communicate with Android Service using IPC (1)

Activity Service

ServiceConnection

onServiceConnected()

onServiceDisconnected()

bindService() onBind()

IMyInterface.aidl

IMyInterface.Stub

onDestroy()

mMyInterface = IMyInterface.Stub.asInterface(service); mMyInterface.registerCallback(cb);

RemoteCallbackList<IMyCallback> IMyCallback.aidl

mMyInterface.unregisterCallback(cb);

unbindService()

mMyInterface.unregisterCallback(cb); onUnbind()

Communicate with Android Service using IPC (2)

• AIDL types restrictions: – Primitives – String, CharSequence – List, Map – Other AIDL interfaces (import needed) – Parcelable classes (import needed)

• No Exceptions will be send back except RemoteException • All IPC calls are synchronous • Only methods, no fields

public void onCreate() { mCallbacks = new RemoteCallbackList<IMyCallback>(); } public void onDestroy() { mCallbacks.kill(); } IMyInterface.Stub { public void registerCallback(IMyCallback cb) { mCallbacks.register(cb); } public void unregisterCallback(IMyCallback cb) { mCallbacks.unregister(cb); } } private void notifyCallbacks(int data) { final int N = mCallbacks.beginBroadcast(); for (int i = 0; i < N; i++) { try { mCallbacks.getBroadcastItem(i).notify(data); } catch (RemoteException e) {} } mCallbacks.finishBroadcast(); }

Bundle, Parcel, Parcelable

Parcel

Bundle

key1 Value<int>

key2 Value<String>

key3 Value<ArrayList>

key4 Value<Parcelable>

key5 Value<Serializable>

...

Primitives

Primitive Arrays[]

Untyped Containers

writeValue(Object)

Object readValue()

Active Objects

IBinder IInterface

ParcelFileDescriptor

Parcelable

public class MyParcelable implements Parcelable {

int mData;

public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() { public MyParcelable createFromParcel(Parcel in) {return new MyParcelable(in);} public MyParcelable[] newArray(int size) {return new MyParcelable[size];} };

private MyParcelable(Parcel in) {mData = in.readInt();}

@Override

public int describeContents() {return 0;} @Override

public void writeToParcel(Parcel out, int flags) {out.writeInt(mData);} }

parcelable MyParcelable;

Java

AIDL

Agenda

• Debugging hints and tools

• Dealing with screen orientation

• Memory leaks analysis

• Working with Services

• Databases

• XML parsers

• Input methods, Search providers

• Battery life, wakelocks

• Flurry

• Publishing to Android Market

Databases (1)

• Create database easily with SQLiteOpenHelper

private static class DatabaseHelper extends SQLiteOpenHelper { DatabaseHelper() { super(VKApplication.getAppContext(), DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE IF NOT EXISTS " + DATABASE_TABLE_FRIENDS + " (" + KEY_FRIEND_ID + " TEXT PRIMARY KEY," + KEY_FRIEND_NAME + " TEXT, “ + KEY_FRIEND_AVATAR + " TEXT, " + KEY_FRIEND_PHONE + " TEXT, " + KEY_FRIEND_EMAIL + " TEXT);"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE_FRIENDS); onCreate(db); } }

mDb.query(DATABASE_TABLE_FRIENDS, null, null, null, null, null, null); //Cursor

Databases (2)

• If you need DB on SD – you should handle this on your own

String databasePath = Environment.getExternalStorageDirectory() + SLASH_DELIMITER + DATABASE_DIR + SLASH_DELIMITER + DATABASE_FILENAME; if (isSdMounted()) { try { mDb = SQLiteDatabase.openDatabase(databasePath, null, SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.NO_LOCALIZED_COLLATORS); checkAndUpgradeDb(mDb); } catch (SQLiteException sqle) { File folder = new File(Environment.getExternalStorageDirectory() + SLASH_DELIMITER + DATABASE_DIR); if (!folder.exists()) { folder.mkdirs(); } mDb = SQLiteDatabase.openDatabase(databasePath, null, SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.NO_LOCALIZED_COLLATORS); db.execSQL(SQL_CREATE_DB); db.setVersion(DATABASE_VERSION); } } }

Let’s Have a Break! 10 min

Agenda

• Debugging hints and tools

• Dealing with screen orientation

• Memory leaks analysis

• Working with Services

• Databases

• XML parsers

• Input methods, Search providers

• Battery life, wakelocks

• Flurry

• Publishing to Android Market

SAX

• Event-driven (faster parsering)

• Minimize memory footprints

• org.xml.sax.helpers.DefaultHandler

public class MyXmlHandler extends DefaultHandler{ @Override public void characters(char[] ch, int start, int length) throws SAXException {} @Override public void endElement(String uri, String localName, String name) throws SAXException {} @Override public void startDocument() throws SAXException {} @Override public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {} … }

http://www.saxproject.org/

Easier SAX

• android.sax - a framework that makes it easy to write efficient and robust SAX handlers

RootElement root = new RootElement("rss"); final List<Message> messages = new ArrayList<Message>(); Element channel = root.getChild("channel"); Element item = channel.getChild(ITEM); item.setEndElementListener(new EndElementListener(){ public void end() { messages.add(currentMessage.copy()); } }); item.getChild(TITLE).setEndTextElementListener(new EndTextElementListener(){ public void end(String body) { currentMessage.setTitle(body); } }); … try { Xml.parse(this.getInputStream(), Xml.Encoding.UTF_8, root.getContentHandler()); } catch (Exception e) {}

ElementListener EndElementListener EndTextElementListener StartElementListener TextElementListener Element RootElement

DOM

• You require access to the entire document (XSLT)

• XML validation, random access DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); List<Message> messages = new ArrayList<Message>(); try { DocumentBuilder builder = factory.newDocumentBuilder(); Document dom = builder.parse(this.getInputStream()); Element root = dom.getDocumentElement(); NodeList items = root.getElementsByTagName(ITEM); for (int i=0;i<items.getLength();i++){ Message message = new Message(); Node item = items.item(i); NodeList properties = item.getChildNodes(); for (int j=0;j<properties.getLength();j++){ Node property = properties.item(j); String name = property.getNodeName(); if (name.equalsIgnoreCase(TITLE)){ message.setTitle(property.getFirstChild().getNodeValue()); } else if (){ … } messages.add(message); } } catch (Exception e) { throw new RuntimeException(e); } javax.xml.parsers.DocumentBuilder

XML Pull (similar to StAX)

• A median between tree based and event based approaches

List<Message> messages = null; XmlPullParser parser = Xml.newPullParser(); try { // auto-detect the encoding from the stream parser.setInput(this.getInputStream(), null); int eventType = parser.getEventType(); Message currentMessage = null; boolean done = false; while (eventType != XmlPullParser.END_DOCUMENT && !done){ String name = null; switch (eventType){ case XmlPullParser.START_DOCUMENT: messages = new ArrayList<Message>(); break; case XmlPullParser.START_TAG: name = parser.getName(); if (name.equalsIgnoreCase(ITEM)){ currentMessage = new Message(); } else if (currentMessage != null){ if (name.equalsIgnoreCase(LINK)){ currentMessage.setLink(parser.nextText()); } else if (…)){ … } } break;

case XmlPullParser.END_TAG: … break; } eventType = parser.next(); } } catch (Exception e) { throw new RuntimeException(e); }

Agenda

• Debugging hints and tools

• Dealing with screen orientation

• Memory leaks analysis

• Working with Services

• Databases

• XML parsers

• Input methods, Search providers

• Battery life, wakelocks

• Flurry

• Publishing to Android Market

Input Method

• Extend InputMethodService

• <intent-filter> and Settings Activity

Input View

Candidates View

TYPE_CLASS_TEXT TYPE_CLASS_PHONE

onCreate onCreateInput

View()

onCreateCandid

atesView()

onStartInputView()

onFinishInput ()

onDestroy ()

Edit text Move to the next field

Onscreen Input Modes

• EditText attributes: – android:inputType

– android:inputMethod

– android:imeOptions

– android:imeActionId

– android:imeActionLabel

• Resize modes for Activity – android:windowSoftInputMode

android:inputType="textEmailAddress"

android:inputType="phone" android:imeOptions="actionSearch"

["stateUnspecified ", "stateUnchanged", "stateHidden", "stateAlwaysHidden", "stateVisible", "stateAlwaysVisible", "adjustUnspecified“, "adjustResize", "adjustPan"]

Search in Android (1)

Search

Invoke your search UI

Type-to-search feature

Invoke global/local search box

Disable search

onSearchRequested();

setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); // search within your activity setDefaultKeyMode(DEFAULT_KEYS_SEARCH_GLOBAL); // search using platform global search

@Override public boolean onSearchRequested() { return false; }

@Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); final Intent queryIntent = getIntent(); final String queryAction = queryIntent.getAction(); if (Intent.ACTION_SEARCH.equals(queryAction)) { } }

<intent-filter> <action android:name="android.intent.action.SEARCH" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />

Search in Android (2)

• Global Search Box

<!-- Provides search suggestions for words and their definitions. --> <provider android:name="DictionaryProvider" android:authorities="dictionary" android:syncable="false" />

<searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/search_label" android:searchSettingsDescription="@string/settings_description" android:includeInGlobalSearch="true" android:searchSuggestAuthority="dictionary" android:searchSuggestIntentAction="android.intent.action.VIEW"> </searchable>

Agenda

• Debugging hints and tools

• Dealing with screen orientation

• Memory leaks analysis

• Working with Services

• Databases

• XML parsers

• Input methods, Search providers

• Battery life, wakelocks

• Flurry

• Publishing to Android Market

Coding for Battery Life

• Why does this matter? – Each device has “battery budget”. When it’s gone, it’s gone.

– Apps need to work together to be good citizens of that shared resource

1340mAh 1340mAh 1400mAh

HTC G1 HTC Magic Motorola Droid

Where does it all go?

Watching YouTube: 340mA = 3.4 hours Browsing 3G web: 225mA = 5 hours Airplane mode idle: 2mA = 24 days

Example

• RSS feed reader (phone is in idle) – App wakes up every 10 minutes to update

– Takes about 8 seconds to update, 350mA

– Cost during a given hour: • 3600 seconds * 5mA = 5mAh resting

• 6 times * 8 sec * 350mA = 4.6 mAh updating

• Just one app waking up can trigger cascade

• Bulk data transfer 6MB song from: – EDGE (90kbps): 300mA * 9.1 min = 45 mAh

– 3G (300kbps): 210mA * 2.7 min = 9.5 mAh

– Wi-Fi (1Mbps): 330mA * 48 sec = 4.4 mAh

What developer can do? (1)

• Respect user’s settings

• Check network connection – wait for 3G or Wi-Fi

NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); If(info == null ||!mConnectivityManager.getBackgroundDataSetting()){ return false; }

Subscribe to “android.net.conn.BACKGROUND_DATA_SETTING_CHANGED”

int netType = info.getType(); int netSubtype = info.getSubtype(); if (netType == ConnectivityManager.TYPE_WIFI) { return info.isConnected(); } else if (netType == ConnectivityManager.TYPE_MOBILE && netSubtype == TelephonyManager.NETWORK_TYPE_UMTS && !mTelephony.isNetworkRoaming()) { return info.isConnected(); } else { return false; }

Networking

What developer can do? (2)

• Use efficient data format and parser

Networking

What developer can do? (3)

• Be careful with Wakelocks – Wakelocks are costly

– Pick lowest level possible, use specific timeouts

– Consider using android:keepScreenOn to ensure correctness

• Use coarse network location, it’s much cheaper – GPS: 25 seconds * 140mA = 1mAh

– Network: 2 seconds * 180mA = 0.1mAh

• Float math is expensive

• Produce less garbage

Foreground apps

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag"); wl.acquire(); … wl.release();

Accelerometer sensor:

- Normal: 10mA (orientation)

- Game: 80mA

- Fastest: 90mA

GOOD Wakelock

@Override

protected void onResume() {

...

PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);

mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "GTUG");

mWakeLock.acquire();

...

}

@Override

protected void onPause() {

...

mWakeLock.release();

...

}

BAD Wakelock

@Override

protected void onCreate(Bundle savedInstanceState) {

...

PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);

mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "GTUG");

mWakeLock.acquire();

...

}

@Override

protected void onDestroy() {

...

mWakeLock.release();

...

}

Holding wakelock in background

GOOD hardware resource handling

@Override

protected void onResume() {

...

camera = Camera.open();

...

}

@Override

protected void onPause() {

...

camera.release();

...

}

BAD hardware resource handling

@Override

protected void onCreate(Bundle savedInstanceState) {

...

camera = Camera.open();

...

}

@Override

protected void onDestroy() {

...

camera.release();

...

}

Not releasing hardware resources

Debugging

• adb bugreport >> 1.txt

– analyse “DUMP OF SERVICE power” section

– analyse “DUMP OF SERVICE media.camera” section

– …

• adb shell dumpsys battery

• adb shell dumpsys batteryinfo

• adb shell dumpsys power

What developer can do? (4)

• Services should be short-lived; these aren’t daemons

• Trigger wake-up through AlarmManager – stopSelf() when finished

• Start your service using <receiver> in manifest – Intent.ACTION_TIMEZONE_CHANGED,

– ConnectivityManager.CONNECTIVITY_ACTION

– Intent.ACTION_DEVICE_STORAGE_LOW

– Intent.ACTION_BATTERY_LOW

– Intent.ACTION_MEDIA_MOUNTED

Background apps

AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, MyService.class); PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0); long interval = DateUtils.MINUTE_IN_MILLIS * 30; long firstWake = System.currentTimeMillis() + interval; am.setRepeating(AlarmManager.RTC, firstWake, interval, pendingIntent);

Update every 30 min Don’t wake-up device

<receiver android:name=".ConnectivityReceiver" android:enabled="false"> ... </receiver>

ComponentName receiver = new ComponentName(context, ConnectivityReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);

What developer can do? (5)

• Use setInexactRepeating()

• Check current battery and network state before running full update

Background apps

public void onCreate() { // Register for sticky broadcast and send default registerReceiver(mReceiver, mFilter); mHandler.sendEmptyMessageDelayed(MSG_BATT, 1000); } IntentFilter mFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { // Found sticky broadcast, so trigger update unregisterReceiver(mReceiver); mHandler.removeMessages(MSG_BATT); mHandler.obtainMessage(MSG_BATT, intent).sendToTarget(); } };

Agenda

• Dealing with screen orientation

• Memory leaks analysis

• Working with Services

• XML parser

• Databases

• Input methods, Search providers

• Debugging hints and tools

• Battery life, wakelocks

• Flurry

• Publishing to Android Market

Mobile Analytics: Flurry, Motally, others

http://www.flurry.com/

http://www.motally.com/

Flurry

• The easy way to analyze your application usage

• How to: – Register, obtain application KEY

– Set permissions

– Put FlurryAgent.jar in /libs

– Make calls from code

Demo

http://www.flurry.com/

public void onStart() { super.onStart(); FlurryAgent.onStartSession(this, "Y9QZANAAAAYZP32CGI44"); }

public void onStop() { super.onStop(); FlurryAgent.onEndSession(this); }

FlurryAgent.onEvent

FlurryAgent.onError

Agenda

• Dealing with screen orientation

• Memory leaks analysis

• Working with Services

• XML parser

• Databases

• Input methods, Search providers

• Debugging hints and tools

• Battery life, wakelocks

• Flurry

• Publishing to Android Market

Signing your apps for Android Market (1)

• Debug signature vs Private key signature

• Sign with the same certificate: – Application upgrade

– Run in the same process

– Data sharing through permissions

• zipalign tool

• Eclipse export tool

Debug certificate:

Keystore name: "debug.keystore"

Keystore password: "android"

Key alias: "androiddebugkey"

Key password: "android"

CN: "CN=Android Debug,O=Android,C=US"

zipalign -v 4 your_project_name-unaligned.apk your_project_name.apk

Signing your apps for Android Market (2)

• Before publishing don’t forget: – Turnoff any Log

– Specify correct versionCode, versionName, min & target SDK versions

– Obtain Map key (http://code.google.com/android/add-ons/google-apis/mapkey.html) if you are using MapView

– Sign application with private key (a validity period ending after 22 October 2033)

Demo

http://market.android.com/publish

Android Market application on device

Intent intent = new Intent(Intent.ACTION_VIEW);

intent.setData(Uri.parse(mMarketUrl));

try {

startActivity(intent);

} catch (ActivityNotFoundException e) {

// no market

}

market://details?id=<packagename>

market://search?q=pname:<package>

market://search?q=pub:<Developer Name>

market://search?q=<substring>

Devices without Android Market

• Download .apk to SD card

• Check «allow non-market applications» setting

• Run Package Installer

int result = Settings.Secure.getInt(getContentResolver(),

Settings.Secure.INSTALL_NON_MARKET_APPS, 0);

if (result == 0) {

// some dialog here

} else {

Intent intent = new Intent(Intent.ACTION_VIEW);

intent.setDataAndType(Uri.fromFile(new File(mLocalInstallationFileName)), “

application/vnd.android.package-archive");

startActivity(intent);

finish();

}

Intent intent = new Intent();

intent.setAction(Settings.ACTION_APPLICATION_SETTINGS);

startActivity(intent);

Check for updates manually!

Install application from app memory

• Download .apk to the app memory getAppContext().getCacheDir().getPath()

• Use out = getAppContext().openFileOutput(mFileName, Context.MODE_WORLD_READABLE);

• Run installation File realFilePath = context.getFileStreamPath(mFileName); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(realFilePath), "application/vnd.android.package-archive"); context.startActivity(intent);

QR codes

• http://qrcode.kaywa.com/

• http://zxing.appspot.com/generator/

• http://code.google.com/p/zxing/

market://search?q=pname:com.google.zxing.client.android

ZXing Barcode Scanner

We didn’t tell you about…

• Sensor

• Location

• Media

• Testing and Instrumentation

• OpenGL

• Gestures (since SDK4)

• AccountManager (since SDK 5)

• SparseBooleanArray

• PorterDuffXfermode

• A lot more…

Future reading

• Application signing - http://developer.android.com/guide/publishing/app-signing.html

• Take screenshots through command line - http://android.amberfog.com/?p=168

• Parsers in Adroid - http://www.ibm.com/developerworks/opensource/library/x-android/index.html

• DEX decompiler - http://code.google.com/p/smali/

Recommended Blogs

• http://android-developers.blogspot.com/

• http://kohlerm.blogspot.com/ (Memory)

• http://jeremymanson.blogspot.com/ (Java)

• http://android.amberfog.com/

• http://androidandme.com/

• http://www.androidguys.com/

• http://phandroid.com/

• …

Partners

Contacts

Dmitry Lukashev

http://ru.linkedin.com/in/dmitrylukashev

dmitry.lukashev@gmail.com

Blog - http://android.amberfog.com/

Alexey Golubev

http://ru.linkedin.com/in/golubevalexey

goalstudio@gmail.com

Thank You!

Questions?

AudioTrack sample

public class AudioTrackSample implements Runnable {

private static final int sBufferSize = 8000;

private AudioTrack mTrack;

private short mBuffer[];

private short mSample;

class AudioTrackSample {

mBuffer = new short[sBufferSize];

mTrack = new AudioTrack(STREAM_MUSIC, 44100, CHANNEL_OUT_MONO,

ENCODING_PCM_16BIT, sBufferSize * 2, MODE_STREAM);

mSample = 0;

}

public void run() {

mTrack.play();

while(1) {

// fill the buffer

generateTone(mBuffer, sBufferSize);

mTrack.write(mBuffer, 0, sBufferSize);

}

}

public void generateTone(short [] data, int size) {

for (int i = 0; i < size; i++) {

pData[i] = mSample;

mSample += 600; // ~400 Hz sawtooth

}

AudioTrack JNI sample

public class JNISample implements Runnable {

private static final int sBufferSize = 8000;

private AudioTrack mTrack;

private short mBuffer[] = new short[sBufferSize];

private int mSample;

class JNISample {

mBuffer = new short[bufferSize];

mTrack = new AudioTrack(STREAM_MUSIC, 44100, CHANNEL_OUT_MONO,

ENCODING_PCM_16BIT, sBufferSize * 2, MODE_STREAM);

mSample = 0;

}

public void run() {

mTrack.play();

while(1) {

// fill the buffer

generateTone(mBuffer, sBufferSize);

mTrack.write(mBuffer, 0, sBufferSize);

}

}

static {

System.loadLibrary(“generate_tone”);

}

public native int generateTone(short [] data, int size);

}

AudioTrack JNI sample (cont.)

jint Java_com_example_jnisample_JNISample_generateTone(

JNIEnv *env, jobject thiz, jshortArray data, jint size)

{

if (size <= 0) {

return ERR_NO_DATA;

}

// convert java short array to C pointer, pinning the array in memory

pData = (short*) env->GetPrimitiveArrayCritical(data, NULL);

if (!pData) {

return ERR_NO_DATA;

}

// fill buffer with 16-bit PCM audio

short sample = 0;

for (int i = 0; i < size; i++) {

pData[i] = sample;

sample += 600; // ~400 Hz tone

}

// unpin the array

env->ReleasePrimitiveArrayCritical(data, pData, 0);

return SUCCESS;

}

AudioRecord JNI sample

AudioRecord arec = null;

try {

int buffersize = AudioRecord.getMinBufferSize(INPUT_FREQUENCY,

AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT) * 10;

int actualbuffersize = buffersize * 10;

arec = new AudioRecord(MediaRecorder.AudioSource.MIC, INPUT_FREQUENCY,

AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,

actualbuffersize);

while (!stop) {

int read = arec.read(audioBuffer, frameSize);

if (stop) {

break;

}

processBuffer(read);

}

} catch ...

private native void processBuffer(int size) throws IOException;

Android 2.2 aka Froyo

Changes

New User Features - Keyboard

• Number pad and punctuation: swipe up from the keyboard to reveal two additional rows of keys.

• Change language: swipe left and right across the space bar will cycle the keyboard through any installed system languages.

New User Features – Share internet connection

• Portable Wi-Fi hotspot (can be shared with up to 8 devices)

• USB Tethering - using your phone as a modem via USB

New User Features – Improved performance

• Faster JavaScript in browser (V8 engine)

• Dalvik JIT

• Kernel Memory Management Boost (improved memory reclaim, faster app switching)

New User Features – Misc (1)

• Tips widget, fixed shortcuts to Phone and Browser

• Exchange support

• Improved Gallery and Camera

• New Android Market app: auto update/update all

• Copy/Past in E-mail application

New User Features – Misc (2)

• Drop-out menus in search

• Improved application manager

• Adobe Flash support (10.1 beta – downloadable from Android Market)

New Platform Technologies

• Media framework – New media framework (Stagefright) that supports local file

playback and HTTP progressive streaming – Continued support for OpenCore in Android 2.2

• Bluetooth – Voice dialing over Bluetooth – Ability to share contacts with other phones – Support for Bluetooth enabled car and desk docks – Improved compatibility matrix with car kits and headsets

• 2.6.32 kernel upgrade – HIGHMEM support for RAM >256MB – SDIO scheduling and BT improvements

What’s new for developer?

Alexey brings gifts to Droid at Google IO ‘09

Cloud to Device Messaging Framework

• It allows third-party application servers to send lightweight messages to their Android applications.

• C2DM makes no guarantees about delivery or the order of messages

• An application on an Android device doesn’t need to be running to receive messages

http://code.google.com/android/c2dm/

Android Application Error Reports

• Automatic crash reports

• Statistics available at Android Market Management console

android.app.admin

• Public interface for managing policies enforced on a device • <uses-policies>

<limit-password /> <watch-login /> <reset-password /> <force-lock /> <wipe-data /> </uses-policies>

• http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.html

android.app.backup

• Perform backup of arbitrary data to remote storage

• Easily perform backup of SharedPreferences and files

• Restore the data saved to remote storage • http://developer.android.com/guide/topics/data/backup.html

• New bmgr tool for testing http://developer.android.com/guide/developing/tools/bmgr.html

android.os

• DropBoxManager – Enqueues chunks of data. You can think of this as a persistent, system-

wide, blob-oriented "logcat".

– DropBoxManager entries are not sent anywhere directly, but other system services and debugging tools may scan and upload entries for processing

• RecoverySystem – RecoverySystem contains methods for interacting with the Android

recovery system (the separate partition that can be used to install system updates, wipe user data, etc.)

android.app

• SearchableInfo

– Searchability meta-data for an activity. Only applications that search other applications should need to use this class

– http://developer.android.com/guide/topics/search/searchable-config.html

• UiModeManager

– This class provides access to the system uimode services

– It provides functionality to disable the car mode and it gives access to the night mode setting

android.content

• DialogInterface.OnShowListener – Interface used to allow the creator of a dialog to run some code when the dialog

is shown

• Entity and EntityIterator – A representation of a item using ContentValues. Useful in Contacts

• PeriodicSync – Value type that contains information about a periodic sync

• SyncInfo – Information about the sync operation that is currently underway

android.media

• AudioManager.OnAudioFocusChangeListener

• MediaScannerConnection.OnScanCompletedListener

• SoundPool.OnLoadCompleteListener

• CamcorderProfile – The CamcorderProfile class is used to retrieve the predefined camcorder

profile settings for camcorder applications. These settings are read-only.

• CameraProfile – The CameraProfile class is used to retrieve the pre-defined still image

capture (jpeg) quality levels (0-100) used for low, medium, and high quality settings in the Camera application.

• ThumbnailUtils – Thumbnail generation routines for media provider.

android.net and android.net.http

• SSLSessionCache – File-based cache of established SSL sessions. This is a persistent cache

which can span executions of the application

• TrafficStats – Class that provides network traffic statistics. These statistics include

bytes transmitted and received and network packets transmitted and received, over all interfaces, over the mobile interface, and on a per-UID basis.

• AndroidHttpClient – Subclass of the Apache DefaultHttpClient that is configured with

reasonable default settings and registered schemes for Android

• SslError – One or more individual SSL errors and the associated SSL certificate

android.view and android.gesture

• ScaleGestureDetector

• ScaleGestureDetector.OnScaleGestureListener

• ScaleGestureDetector.SimpleOnScaleGestureListener

• GestureUtils – Utility functions for gesture processing & analysis

– feature extraction (e.g., samplers and those for calculating bounding boxes and gesture path lengths);

– geometric transformation (e.g., translation, rotation and scaling);

– gesture similarity comparison (e.g., calculating Euclidean or Cosine distances between two gestures).

android.speech

• RecognitionListener – Used for receiving notifications from the SpeechRecognizer when the

recognition related events occu

• RecognitionService and RecognitionService.Callback – This class provides a base class for recognition service implementations

– This class should be extended only in case you wish to implement a new speech recognizer

• SpeechRecognizer – This service allows access to the speech recognizer

Other

android.hardware Camera.OnZoomChangeListener android.webkit ConsoleMessage ConsoleMessage.MessageLevel WebSettings.PluginState android.test.mock MockContentProvider MockCursor android.text.style LeadingMarginSpan.LeadingMarginSpan2

android.util Base64 Base64InputStream Base64OutputStream EventLog EventLog.Event Patterns

Thank You!

Recommended