android in action (part iii)

107
Android in Action (part III) Alexey Golubev, Dmitry Lukashev

Upload: others

Post on 12-Sep-2021

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Android in Action (part III)

Android in Action (part III)

Alexey Golubev, Dmitry Lukashev

Page 2: Android in Action (part III)

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.

Page 3: Android in Action (part III)

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

Page 4: Android in Action (part III)

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

Page 5: Android in Action (part III)

Debugging tools

• Android Debug Bridge (ADB)

• Dalvik Debug Monitor Server (DDMS)

• Traceview

• logcat

• ADT plug-in

• DevTools

• SpareParts

• AXMLPrinter2

Page 6: Android in Action (part III)

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

Page 7: Android in Action (part III)

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

Page 8: Android in Action (part III)

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

Page 9: Android in Action (part III)

DDMS

• Threads info

• VM Heap info

• Allocation Tracker

• System info

• Emulator control

• Screen capture

• File Explorer

Demo

Page 10: Android in Action (part III)

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" ... />

Page 11: Android in Action (part III)

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

Page 12: Android in Action (part III)

Spare Parts

• Battery history

• Usage statistics

Page 13: Android in Action (part III)

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> …

Page 14: Android in Action (part III)

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

Page 15: Android in Action (part III)

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()

Page 16: Android in Action (part III)

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()!

Page 17: Android in Action (part III)

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>

Page 18: Android in Action (part III)

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

Page 19: Android in Action (part III)

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)

Page 20: Android in Action (part III)

Memory Leaks demo

Page 21: Android in Action (part III)

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

Page 22: Android in Action (part III)

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

Page 23: Android in Action (part III)

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

Page 24: Android in Action (part III)

Memory Analyzer demo

Page 25: Android in Action (part III)

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

Page 26: Android in Action (part III)

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".../>

Page 27: Android in Action (part III)

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()

Page 28: Android in Action (part III)

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!

Page 29: Android in Action (part III)

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

Page 30: Android in Action (part III)

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()

Page 31: Android in Action (part III)

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(); }

Page 32: Android in Action (part III)

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

Page 33: Android in Action (part III)

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

Page 34: Android in Action (part III)

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

Page 35: Android in Action (part III)

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); } } }

Page 36: Android in Action (part III)

Let’s Have a Break! 10 min

Page 37: Android in Action (part III)

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

Page 39: Android in Action (part III)

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/

Page 40: Android in Action (part III)

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

Page 41: Android in Action (part III)

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

Page 42: Android in Action (part III)

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); }

Page 43: Android in Action (part III)

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

Page 44: Android in Action (part III)

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

Page 45: Android in Action (part III)

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"]

Page 46: Android in Action (part III)

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" />

Page 47: Android in Action (part III)

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>

Page 48: Android in Action (part III)

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

Page 49: Android in Action (part III)

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

Page 50: Android in Action (part III)

Where does it all go?

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

Page 51: Android in Action (part III)

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

Page 52: Android in Action (part III)

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

Page 53: Android in Action (part III)

What developer can do? (2)

• Use efficient data format and parser

Networking

Page 54: Android in Action (part III)

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

Page 55: Android in Action (part III)

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();

...

}

Page 56: Android in Action (part III)

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();

...

}

Page 57: Android in Action (part III)

Holding wakelock in background

Page 58: Android in Action (part III)

GOOD hardware resource handling

@Override

protected void onResume() {

...

camera = Camera.open();

...

}

@Override

protected void onPause() {

...

camera.release();

...

}

Page 59: Android in Action (part III)

BAD hardware resource handling

@Override

protected void onCreate(Bundle savedInstanceState) {

...

camera = Camera.open();

...

}

@Override

protected void onDestroy() {

...

camera.release();

...

}

Page 60: Android in Action (part III)

Not releasing hardware resources

Page 61: Android in Action (part III)

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

Page 62: Android in Action (part III)

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);

Page 63: Android in Action (part III)

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(); } };

Page 64: Android in Action (part III)

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

Page 65: Android in Action (part III)

Mobile Analytics: Flurry, Motally, others

http://www.flurry.com/

http://www.motally.com/

Page 66: Android in Action (part III)

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

Page 67: Android in Action (part III)

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

Page 68: Android in Action (part III)

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

Page 69: Android in Action (part III)

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

Page 70: Android in Action (part III)

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>

Page 71: Android in Action (part III)

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!

Page 72: Android in Action (part III)

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);

Page 73: Android in Action (part III)

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

Page 74: Android in Action (part III)

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…

Page 75: Android in Action (part III)

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/

Page 76: Android in Action (part III)

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/

• …

Page 77: Android in Action (part III)

Partners

Page 78: Android in Action (part III)

Contacts

Dmitry Lukashev

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

[email protected]

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

Alexey Golubev

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

[email protected]

Page 79: Android in Action (part III)

Thank You!

Questions?

Page 80: Android in Action (part III)

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

}

Page 81: Android in Action (part III)

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);

}

Page 82: Android in Action (part III)

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;

}

Page 83: Android in Action (part III)

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;

Page 84: Android in Action (part III)

Android 2.2 aka Froyo

Changes

Page 85: Android in Action (part III)
Page 86: Android in Action (part III)

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.

Page 87: Android in Action (part III)

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

Page 88: Android in Action (part III)

New User Features – Improved performance

• Faster JavaScript in browser (V8 engine)

• Dalvik JIT

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

Page 89: Android in Action (part III)

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

Page 90: Android in Action (part III)

New User Features – Misc (2)

• Drop-out menus in search

• Improved application manager

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

Page 91: Android in Action (part III)

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

Page 92: Android in Action (part III)

What’s new for developer?

Alexey brings gifts to Droid at Google IO ‘09

Page 93: Android in Action (part III)

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/

Page 94: Android in Action (part III)

Android Application Error Reports

• Automatic crash reports

• Statistics available at Android Market Management console

Page 95: Android in Action (part III)

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

Page 96: Android in Action (part III)

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

Page 97: Android in Action (part III)

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.)

Page 98: Android in Action (part III)

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

Page 99: Android in Action (part III)

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

Page 100: Android in Action (part III)

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.

Page 101: Android in Action (part III)

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

Page 102: Android in Action (part III)

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).

Page 105: Android in Action (part III)

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

Page 106: Android in Action (part III)

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

Page 107: Android in Action (part III)

Thank You!