Browser Engines und HTML5
27. Aug
Webentwickler, die mit der Zeit gehen wollen und müssen, werden um HTML5 und CSS3 nicht herumkommen. Warum auch? Gibt es doch viele schöne neue Dinge zu entdecken und wesentlich mehr Möglichkeiten. Wer noch in den 1990er Jahren oder auch in den Anfängen dieses Jahrtausends Webseiten entwickelte, optimierte diese meist für einen speziellen Browser (bzw. eine Engine). Das waren vielfach Optimierungen für den Netscape Navigator oder den Internet Explorer. Glücklicherweise halten sich mittlerweile mehr oder weniger alle auf dem Markt befindlichen Browser (naja, mit eben einer Ausnahme…) an gewisse Standards – so dass die Optimierungen wegfallen.
Dank der anstehenden Finalisierung des HTML5-Standards wird das ganze nochmal einfacher: alle Entwickler der den Browsern zugrunde liegenden HTML Rendering Engines werden den HTML5-Standard adaptieren. Wenn man nun mal mit aktuellen Browsern auf die Seite html5test.com surft, so sieht man, wieviel Punkte der eigene Browser (bzw. seine Rendering Engine) erreicht. Ich habe das mal mit den gängigsten gemacht – ebenso mit meinem HTC Desire (Android 2.2 Froyo) und dem iPhone (iOS 4). Der Maximalwert bei den Punkten beträgt dabei 300.
| Gerät | Engine | Browser | Punkte |
| Android (2.2) | Webkit | Standard Browser (aka Chrome Lite), Dolphin / Dolphin HD, xScope, Steel, | 176 |
| IPhone (iOS 4) | WebKit | Safari | 185 |
| Desktop PC (Windows) | WebKit | Safari (Version 5.0.1) | 207 |
| Desktop PC (Windows) | WebKit | Chrome (Version 5.0) | 197 |
| Desktop PC (Windows) | Presto | Opera (Version 10.61) | 159 |
| Desktop PC (Windows) | Mozilla/5.0 | Firefox (Version 3.6.8) | 139 |
Wie man deutlich erkennen kann, ist eigentlich noch keine Engine wirklich auf dem Stand, HTML5 komplett zu unterstützen. Aber es wird. Interessant dürfte HTML5 dann (vor allem im Einsatz mit CSS3) für mobile Geräte wie eben Androiden und iPhone werden.
Der Vorteil für Webentwickler liegt hier auf der Hand: dadurch, dass beide Gerätetypen den Standard vermutlich weitestgehend erfüllen, kann man gezielt “bessere” Seiten entwickeln – und eben auch weiterentwickeln.
Zwar ist auch meistens noch Support für andere bzw. ältere mobile Geräte zu gewährleisten – aber den Fokus haben wohl eindeutig die neuen Geräte. Es bleibt durchaus ein spannendes Thema, denn die mobilen Geräte unterstützen ja weitestgehend auch JavaScript, und hier gibt es auch schon zwei, drei vielversprechende Bibliotheken, die eine für Touchphones optimierte Darstellung bieten mit den Effekten und Darstellungen, wie man sie auch aus nativen Applikationen kennt (da werde ich aber mal einen separaten Blog-Eintrag für verfassen).
Android User-Agents (HTC Desire)
25. Aug
Nachdem Update auf FroYo scheint es bei einigen HTC Desire-Geräten zu Fehlern im User-Agent zu kommen. Mal ganz davon zu schweigen, dass viele Endgeräte-Datenbanken wie Device Atlas anscheinend eine Erkennungs-Technik einsetzen, die hier nicht wirklich fruchtbar ist.
Nach dem Update meines HTC Desire auf Android 2.2 (“FroYo”) sende ich jedenfalls folgende Kennung (User-Agent):
Bei dieser doch (mittlerweile) eindeutigen Kennung sollte auch das richtige Gerät gefunden werden können.
Wie dem auch sei, darauf wollte ich gar nicht hinaus. Denn viel interessanter ist die Möglichkeit, den User-Agent selbst zu setzen. Zumindest im Standard-Browser von Android ist das möglich (Dolphin unterstützt alternativ zum Original User-Agent nur Desktop und iPhone). Dazu geht man wir folgt vor:
- Standard-Browser öffnen
- in die Adresszeile (ohne http:// etc): about:debug eingeben
- unter Menü -> mehr… -> Einstellungen auswählen
- weit unten UAString auswählen
Hier können nur die vordefinierten User Agent-Kennungen (Android, Desktop, iPhone, iPad) gewählt werden – oder alternativ ein eigener über den Punkt manual definiert werden. Damit sollte man dann auch vom HTC Desire gezielt Erkennungen so manipulieren, dass man wirklich erkannt wird!
Sobald man im about:debug-Modus ist, gibt es übrigens eine Menge weitere Punkte, sowohl im Menü als auch unter Einstellungen.
[HTC Desire] Telefon-Codes
10. Aug
Mehr (oder weniger) interessante Informationen aus dem Handy bekommt man eigentlich bei allen Handys durch sogenannte Codes. Da ich selbst nur ein HTC Desire habe, kann ich nicht sagen, mit welchen Geräten es sonst noch klappt. Wobei die meisten Codes allgemein für Android ausgelegt sein sollten.
Code-Liste
Die Codes werden einfach über die Dialer-App eingegeben. Also so, als würdet ihr eine Nummer anrufen wollen. Bitte vorher auch lesen, was welcher Code bewirkt. Ich übernehme dafür natürlich keine Verantwortung!
| CODE | FUNKTION |
| *135# | Eigene MSISDN anzeigen (funktioniert nicht mit allen Telefonen/Providern) |
| *#*#4636#*#* | Erweiterte Informationen (Testing & Debug-Info) |
| *#*#9696#*#* | FTP Testing |
| *#*#3424#*#* | HTC Function Test Program |
| *#*#8255#*#* | GTalk Service Monitor |
| *#*#7262626#*#* | FieldTest |
| *2767*3855# | Hardreset (Vorsicht: Es werden alle Daten gelöscht!) |
Tastenkombinationen
Zusätzlich gibt es noch einige nützliche Tastenkombinationen, die man kennen sollte:
- Fastboot (im ausgeschalteten Zustand): Back + Power
- Bootmenu (HBOOT) (im ausgeschalteten Zustand): Volume Down + Power
- Neustart (aus dem laufenden Betrieb heraus): Volume Down + optischer Trackball + Power
View und Activity Transitionen
15. Jul
Auf der Suche nach Möglichkeiten Transitionen (also Übergangseffekten) zwischen Activities und/oder Views in Android zu implementieren, habe ich viele interessante Artikel gefunden. Im diesem Beitrag zeige ich zwei grundsätzliche Möglichkeiten auf, diese Effekte zu realisieren. Zunächst eine Transition zwischen zwei Views innerhalb einer Activity und anschließend eine Transition zwischen zwei Activities. Beide Projekte gibt es auch zum Download im jeweiligen Abschnitt.
View-to-View Transition
Je nach Vorhaben reicht es manchmal aus, die View einer Activity zu wechseln, anstatt gleich eine zweite (Activity) zu implementieren. Um hier einen Effekt zu erzielen, wird die Klasse ViewFlipper (verfügbar ab API-Level 1) aus dem Android-SDK verwendet und mit Animationen (Android Developers | Animation) versehen.
Hier eine kurze Demo, wie das ganze aussehen wird:
Die Views (ImageView, klappt aber natürlich auch mit allen anderen) werden also via Animation ausgetauscht (in diesem Fall “fliegen” sie zur Ecke hinaus). Folgender Code zeichnet sich dafür verantwortlich:
/res/layout/main.xml
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/flipper"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<include android:id="@+id/first" layout="@layout/view1" />
<include android:id="@+id/second" layout="@layout/view2" />
</ViewFlipper>
Ein ViewFlipper dient als Container für die Views (die in diesem Fall per include eingebunden werden, um den Code modularer zu halten).
public class FlipLaunch extends Activity {
private ViewFlipper flipper;
private Animation hideFirstView() {
final Animation outtoLeft = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, -1.0f,
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, -1.0f);
outtoLeft.setDuration(500);
outtoLeft.setInterpolator(new AccelerateInterpolator());
return outtoLeft;
}
private Animation hideSecondeView() {
final Animation outToRight = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, +1.0f,
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, +1.0f);
outToRight.setDuration(500);
outToRight.setInterpolator(new AccelerateInterpolator());
return outToRight;
}
private Animation showFirstView() {
final Animation inFromLeft = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT, -1.0f,
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, -1.0f,
Animation.RELATIVE_TO_PARENT, 0.0f);
inFromLeft.setDuration(500);
inFromLeft.setInterpolator(new AccelerateInterpolator());
return inFromLeft;
}
private Animation showSecondView() {
final Animation inFromRight = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT, +1.0f,
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, +1.0f,
Animation.RELATIVE_TO_PARENT, 0.0f);
inFromRight.setDuration(500);
inFromRight.setInterpolator(new AccelerateInterpolator());
return inFromRight;
}
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
flipper = (ViewFlipper) findViewById(R.id.flipper);
ImageView view1 = (ImageView) findViewById(R.id.image1);
ImageView view2 = (ImageView) findViewById(R.id.image2);
view1.setOnClickListener(new View.OnClickListener() {
public void onClick(final View view) {
flipper.setInAnimation(showSecondView());
flipper.setOutAnimation(hideFirstView());
flipper.showNext();
}
});
view2.setOnClickListener(new View.OnClickListener() {
public void onClick(final View view) {
flipper.setInAnimation(showFirstView());
flipper.setOutAnimation(hideSecondeView());
flipper.showPrevious();
}
});
}
}
Der ViewFlipper beherbergt also zwei Views. Der Einfachheit halber werden diese mit onClick-Methoden ausgestattet. Das Interessante: bei Klicken einer View werden im ViewFlipper zwei Animationen gesetzt:
Download (Eclipse-Projekt)
Android FlipView Demo (247)
Activity-to-Activity Transition
Seit Android 2.0 gibt es darüberhinaus auch die Möglichkeit, die Art des Übergangs zwischen zwei Activities zu steuern – über die Methode Activity.overridePendingTransition(int, int). Allerdings kann dies vom Nutzer deaktiviert werden. Ausserdem gilt der Übergang nicht bei der Back-Navigation.
Hier zunächst wieder eine Demo, wie es aussehen wird:
Zunächst werden zwei Layouts (eine für jede der Activities) geschrieben:
/res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="@+id/image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitXY"
android:src="@drawable/image1" />
</LinearLayout>
/res/layout/second.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="@+id/image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitXY"
android:src="@drawable/image2" />
</LinearLayout>
Zusätzlich benötigen wir noch zwei Animationen (wie auch bei der FlipView: in und out). Diese konfigurieren wir dieses mal über XML. Sollte noch kein Ordner /res/anim vorhanden sein, so muss dieser erstellt werden.
/res/anim/in.xml
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="@android:integer/config_longAnimTime" />
/res/anim/out.xml
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="@android:integer/config_longAnimTime" />
Die beiden Activities sehen relativ gleich aus. Daher zeige ich an dieser Stelle nur die erste:
public class TransitionLaunch extends Activity implements OnClickListener {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView imageView = (ImageView) findViewById(R.id.image);
imageView.setOnClickListener(this);
}
/** @see android.view.View.OnClickListener#onClick(android.view.View) */
@Override
public void onClick(View v) {
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
this.finish();
overridePendingTransition(R.anim.in, R.anim.out);
}
}
Das Geheimnis liegt im abschliessenden Aufruf der Methode Activity.overridePendingTransition(int, int). Über das XML können hier beliebige Animationen gebastelt werden.
Der Aufruf von finish() bewirkt darüber hinaus, dass die Activity beendet wird und somit nicht mehr über die Back-Navigation erreicht werden kann. Daher sollte man in einer echten Applikation Buttons für die Navigation verwenden.
Download (Eclipse-Projekt)
Android Transition Demo (256)
User Notification
23. Jun
Android stellt zwei sehr wirksame und gleichzeitig einfache Möglichkeiten bereit, den Benutzer einer Applikation über Ereignisse zu informieren oder ihn mit Hinweisen zu versorgen. Über Toast (OnScreen-Nachrichten) kann man sehr kurze Hilfen und/oder Rückmeldungen einblenden – oder aber man hinterlässt dem Benutzer eine Mitteilung in der StatusBar.
Um das kurz zu verdeutlichen schon mal vorab zwei Screenshots einer kleinen Demo-Applikation (Download-Link am Ende des Artikels):

Auf dem linken Bild ist im unteren Bereich eine Mitteilung über Toast zu sehen, auf dem rechten Bild die wohl jedem bekannte StatusBar. Im folgenden zeige ich, wie Benutzer auf diese Weisen benachrichtigt werden können.
Toast
Die Möglichkeit, dem Benutzer eine Toast-Mitteilung anzuzeigen ist das wohl an Einfachheit nicht zu überbieten (wenn man es denn weiß):
Context context = getApplicationContext(); String text = "[Demo] Toast Notification"; int duration = Toast.LENGTH_SHORT; Toast toast = Toast.makeText(context, text, duration); toast.show();
Und schon erscheint die Meldung für eine kurze Dauer, die natürlich angepasst werden kann. Der Code dürfte selbsterklärend sein und wird von mir nicht weiter erläutert.
StatusBar-Notification
Etwas (aber auch nicht viel) mehr Code wird benötigt, um dem Benutzer eine Benachrichtigung in die StatusBar zu legen. Der Code dazu sieht wir folgt aus:
// NotificationManager vom System holen String ns = Context.NOTIFICATION_SERVICE; NotificationManager notificationManager = (NotificationManager) getSystemService(ns); // Benachrichtigung erzeugen (samit Icon, Ticker-Text, Zeit) int icon = R.drawable.help; String tickerText = "Statusbar-Notifizierung"; long when = System.currentTimeMillis(); Notification notification = new Notification(icon, tickerText, when); // Intent erstellen für den NotificationManager Context context = getApplicationContext(); String contentTitle = "Notifizierung"; String contentText = "Klicken um mehr zu sehen..."; Intent notificationIntent = new Intent(this, <Activity/Service>.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent); // Flag um die Benachrichtigung automatisch zu entfernen (nach dem Aufrufen) notification.flags |= Notification.FLAG_AUTO_CANCEL; // Benachrichtigung senden notificationManager.notify(<ID>, notification);
Download
* Android Notification Demo (262)
Quellen
* Android Developer Guide | Creating Toast Notifications
* Android Developer Guide | Creating Status Bar Notifications