XDA comet: UMTS/GPRS Bandwechsel / Anwendungsentwicklung Fortschritt

Letzte Woche ist mir an meinem XDA comet aufgefallen, dass er sich relativ häufig abgeschaltet hatte, sprich, dass ein Druck auf den Power-Knopf das Gerät mit der Meldung „Device booting…“ gestartet hatte. Zuvor hatte ich bemerkt, dass beim Gespräch ein „Knacken“ in der Leitung war. Ein kurzer Blick nach dem Gespräch auf das Display zeigte wenig UMTS Empfang, danach vollen GPRS Empfang. Dieser Wechsel erfolgte innerhalb dieser Funkzelle häufiger. Ich persönlich vermute hier, dass weniger die Hardware denn mehr die Software (sprich Windows Mobile 6) unter ungünstigen Umständen Probleme mit diesem Szenario hat. Das trübt aber den bisher durchweg positiven Eindruck von meinem Gerät keineswegs 🙂

Ansonsten bin ich derzeit in meinem „normalen“ Job gefangen, d.h. wir liefern Ende der Woche ein Hauptrelease aus und entsprechend viel Stress und Termindruck wabert durch die Luft. Daher bin ich in der letzten Zeit nur schleppend mit der Anwendungsentwicklung mit dem Compact Framework für Windows Mobile weitergekommen. Jetzt steht aber ab nächster Woche erst einmal Urlaub an und dann sehen wir weiter 😉

WordPress Userlevels in-depth

Vor kurzem hatte ich über das WP-Plugin WP-CodeBox berichtet. Dieses Plugin bietet dem Benutzer auch die Möglichkeit Einstellungen vorzunehmen, was ich mir auch ansehen wollte (vielleicht ist ja etwas interessantes dabei, was default-mäßig ausgeschaltet ist 😉 ).

Leider meinte das Plugin daraufhin:

You are not a LEVEL 8 or above USER & hence you cannot configure WP-CodeBox. If you are a LEVEL 8 or above USER, then please Logout & Login again.

Achso, natürlich, muss ja admin sein. Moment mal, dachte ich mir, du bist doch als admin angemeldet ?! Zuerst wollte ich mir keinen Stress machen, da das Plugin ja funktionierte und so dramatisch waren die Einstellungsmöglichkeiten nun auch wieder nicht. Sicherheitshalber habe ich aber unter dem Tag wp-codebox im WP-Support noch eine Anfrage abgesetzt, wobei ich natürlich prompt das falsche Forum (Installation allgemein) erwischt habe. Die Moderatoren sind aber fit und der Beitrag wurde schnell in das entsprechende Forum verschoben. Das ist schon etwas irreführend gemacht, finde ich.

Nach 5 Tagen kam immer noch keine Antwort oder eine Reaktion, also dachte ich mir, dass ich dann eben diese Prüfung einfach ausbaue. Glücklicherweise war die Prüfung direkt am Anfang des Quelltexts, so dass ich nicht lange suchen musste. Ein kurzer Blick in die WP-Dokumentation förderte die Erkenntnis zu Tage wie der User-Level ermittelt wird. Ein Blick in die Datenbank-Beschreibung ergab, dass der User-Level in der Tabelle wp_usermeta hinterlegt wird, allerdings nicht für den Benutzer admin ??

Was ist denn dann der Default-Wert, zumal das CodeBox-Plugin hier gemeckert hat ? Daher erzeugte ich einen neuen Benutzer, der auch admin-Rechte hat und siehe da, der User-Level wurde in der Tabelle wp_usermeta hinterlegt. Mit diesem Benutzer funktionierte auch der Aufruf der CodeBox-Konfigurationsseite !

Daher hege ich jetzt einfach mal folgenden Verdacht: der Benutzer admin wird irgendwo hart-kodiert abgehandelt, allerdings wird der User-Level für diesen wohl nicht korrekt ermittelt. Doch eine kleine Trübung des bisher durchweg positiven Eindrucks von WordPress. Vielleicht wird das aber auch noch behoben oder ist bekannt. Da ich mich nicht weiter mit der Thematik befasst habe, kann es natürlich auch sein, dass es so sein soll wie es ist. Wer näheres weiß, darf sich gerne zu Wort melden 😉

.Net RowFilter Multi-Wildcard Filter Expressions

In .Net existiert an der Klasse System.Data.DataView ein Property namens RowFilter, das einen Ausdruck in SQL-Syntax erwartet, was wiederum ein Filtern der zugrunde liegenden Daten nach sich zieht. Der Aufbau und die Möglichkeiten des Filterausdrucks werden in in dem Property Expression der Klasse DataColumn beschrieben. Als Wildcards wird der „*“ akzeptiert und ist zugelassen.

Man hat ja von einer freien Filtereingabe die Vorstellung, dass man beliebig Wildcards platzieren kann und der Ausdruck nahezu beliebig komplex werden darf. Doch weit gefehlt: „[…] Wildcards are not allowed in the middle of a string. For example, 'te*xt' is not allowed. […]“ (Quelle: MSDN, ZEICHENFOLGENOPERATOREN).

Was tut man also in einem solchen Fall ? Nun, wenn man sich den Ausdruck 'te*xt' ansieht, so kann man diesen zerlegen in 'te* AND *xt'. Daraus ergibt sich eine Ergebnismenge, die alle Daten beinhaltet, die mit „te“ beginnen und mit „xt“ enden.

Das bedeutet natürlich im Gegenzug, dass man die Erzeugung des Filterausdrucks komplett selbst machen muss. Dafür habe ich mir nun folgendes (und erprobtes) Klassengerüst ausgedacht. Es wird hierbei auf das Factory-Pattern zurückgegriffen (klicken zum Vergrößern):

Filter Klassendiagramm

Hierbei wird auch auf die verschiedenen Editoren und Datentypen Rücksicht genommen. Die Entscheidung, welche Klasse für die Erzeugung des Teilfilterausdrucks (der Ausdruck wird partiell pro Datenspalte erzeugt) genommen wird, erfolgt so:

?View Code CSHARP
this.typesHashtable = new Hashtable();
 
this.typesHashtable.Add(typeof(bool), typeof(BoolGridFilter));
 
this.typesHashtable.Add(typeof(byte), typeof(NumericGridFilter));
this.typesHashtable.Add(typeof(short), typeof(NumericGridFilter));
this.typesHashtable.Add(typeof(int), typeof(NumericGridFilter));
this.typesHashtable.Add(typeof(long), typeof(NumericGridFilter));
this.typesHashtable.Add(typeof(float), typeof(NumericGridFilter));
this.typesHashtable.Add(typeof(double), typeof(NumericGridFilter));
this.typesHashtable.Add(typeof(decimal), typeof(NumericGridFilter));
this.typesHashtable.Add(typeof(UInt16), typeof(NumericGridFilter));
this.typesHashtable.Add(typeof(UInt64), typeof(NumericGridFilter));
 
this.typesHashtable.Add(typeof(DateTime), typeof(DateTimeGridFilter));
 
this.defaultGridFilterType = typeof(TextGridFilter);

Später wird dann mittels Reflection entschieden, welche Klasse genommen werden soll. Dies geschieht über den der DataColumn zugrunde liegenden DataType:

?View Code CSHARP
Type dataType = dc.DataType;
if (dataType != null)
{
  if (this.typesHashtable.ContainsKey(dataType))
  {
    Type gridFilterType = this.typesHashtable[dataType] as Type;
    dcFilter = gridFilterType.Assembly.CreateInstance(gridFilterType.FullName, false,
                       BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance,
                       null, new object[] { dc.DataField, PrepareFilterExpression(dc.FilterText) }, null, new object[] { }) as IDataColumnFilter;
  }
  else
  {
     dcFilter = this.defaultGridFilterType.Assembly.CreateInstance(this.defaultGridFilterType.FullName, false,
                       BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance,
                       null, new object[] { dc.DataField, PrepareFilterExpression(dc.FilterText) }, null, new object[] { }) as IDataColumnFilter;
  }
}

Die hier beschriebenen Code-Fragmente wurden in Verbindung mit dem TrueDBGrid von ComponentOne implementiert, die Architektur ist aber recht lose über Interfaces handhabbar, so dass man die Technik ganz leicht zur Zusammenarbeit mit anderen DataGrids überreden können sollte. Den kompletten Quelltext werde ich hier nicht veröffentlichen, ich hoffe aber, dass dieser Beitrag als Ideengeber dienen kann 😉

Compact Framework Design Time Attribute

Wenn man unter dem .Net Framework entwickelt, kann man Properties in visuellen Klassen (UserControls, Forms, Controls, …) mit Attributen versehen, so dass diese gewisse Eigenschaften haben. Zum Beispiel ist es so möglich ein Property „AlternateText“ in ein eigenes Control einzufügen. Dieses Property ist im Designer auch sichtbar, nachdem man es auf die gerade zu designende Oberfläche per Drag & Drop gezogen hat. Standardmäßig taucht dieses Property in der Kategorie „Misc“ auf. Man kann nun beeinflussen, dass das Property im Properties-Browser im Designer nicht sichtbar ist ([Browsable(false)]), man kann einen Default-Wert festlegen ([DefaulValue(„Not set“)]) oder auch eine eigene Kategorie definieren ([Category(„Advins – Control Visual Properties“)]).

Leider hat man genau diese Annehmlichkeiten nicht im Compact Framework zur Verfügung. Man kann sich aber behelfen, indem man eine XMTA Datei dem Projekt hinzufügt und darin diese Eigenschaften in XML-Form festlegt. Eine solche XML-Datei (DesignTimeAttributes.xmta) kann wie folgt aussehen:

<?xml version="1.0" encoding="utf-16"?>
<Classes xmlns="http://schemas.microsoft.com/VisualStudio/2004/03/SmartDevices/XMTA.xsd">
 <Class Name="AdvControls.ImageButton">
  <Property Name="ButtonText">
   <Browsable>true</Browsable>
   <Category>AdvControls - Properties</Category>
   <Description>Set the text to be displayed in the button here.</Description>
  </Property>
  <Property Name="Image">
   <Browsable>true</Browsable>
   <Category>AdvControls - Properties</Category>
   <Description>Set the image to be displayed in the button here.</Description>
  </Property>
 </Class>
</Classes>

Der Compiler erkennt die Datei und erzeugt daraus eine AdvControls.WindowsCE.asmmeta.dll. So kann man seine Control-Properties doch wie gewohnt (leider nur etwas umständlicher) mit Attributen versehen.

Entwickelt man Code sowohl für den Desktop als auch ein Mobile Device kann man seine Attribute mittels

#if Desktop

#endif

über das Property schreiben ohne Compile-Fehler zu bekommen.

Wiedergabe von Sounds mit dem Compact Framework

Vor einiger Zeit schon stieß ich auf das Problem unter Windows Mobile Sounds wiedergeben zu wollen. Nahezu ohne Weiteres unterstützt wird das Abspielen von WAV-Sounds, aber wie sieht es mit MP3 und/oder WMA aus ? Nun dazu später mehr, hier erst einmal die Lösung von Microsoft, wie man WAV-Sounds unter Windows Mobile abspielen kann:

public class Sound {
private byte[] m_soundBytes;
private string m_fileName;
private enum Flags
{
SND_SYNC = 0x0000, /* play synchronously (default) */
SND_ASYNC = 0x0001, /* play asynchronously */
SND_NODEFAULT = 0x0002, /* silence (!default) if sound not found */
SND_MEMORY = 0x0004, /* pszSound points to a memory file */
SND_LOOP = 0x0008, /* loop the sound until next sndPlaySound */
SND_NOSTOP = 0x0010, /* don’t stop any currently playing sound */
SND_NOWAIT = 0x00002000, /* don’t wait if the driver is busy */SND_ALIAS = 0x00010000, /* name is a registry alias */
SND_ALIAS_ID = 0x00110000, /* alias is a predefined ID */
SND_FILENAME = 0x00020000, /* name is file name */
SND_RESOURCE = 0x00040004 /* name is resource name or atom */
}

[DllImport(„CoreDll.DLL“, EntryPoint=“PlaySound“, SetLastError=true)]
private extern static int WCE_PlaySound(string szSound, IntPtr hMod, int flags);
[DllImport(„CoreDll.DLL“, EntryPoint=“PlaySound“, SetLastError=true)]
private extern static int WCE_PlaySoundBytes (byte[] szSound, IntPtr hMod, int flags);

/// <summary>
/// Construct the Sound object to play sound data from the specified file.
/// </summary>
public Sound (string fileName)
{
m_fileName = fileName;
}

/// <summary>
/// Construct the Sound object to play sound data from the specified stream.
/// </summary>
public Sound(Stream stream)
{
// read the data from the stream
m_soundBytes = new byte [stream.Length];
stream.Read(m_soundBytes, 0,(int)stream.Length);
}

/// <summary>
/// Play the sound
/// </summary>
public void Play ()
{
// if a file name has been registered, call WCE_PlaySound,
// otherwise call WCE_PlaySoundBytes
if (m_fileName != null)
WCE_PlaySound(m_fileName, IntPtr.Zero, (int) (Flags.SND_ASYNC | Flags.SND_FILENAME));
else
WCE_PlaySoundBytes (m_soundBytes, IntPtr.Zero, (int) (Flags.SND_ASYNC | Flags.SND_MEMORY));
}
}

Wie bewerkstelligt man es aber nun, MP3 und WMA-Sounds abzuspielen ? Hierzu fand ich folgende Lösung im Netz:

  • Hinzufügen einer Referenz auf C:\Windows\System32\wmp.dll (man benutzt also den Windows Media Player)
  • Folgenden Code zum Abspielen verwenden:

    WMPLib.WindowsMediaPlayer player = new WMPLib.WindowsMediaPlayer();
    player.URL = „\\Amazing.mp3“;
    player.settings.volume = 100;
    player.controls.next();
    player.controls.play();

Ich greife dieses Thema hier auf, weil mich jüngst Martin per Mail nach einer Lösung fragte und dies vielleicht auch noch für andere interessant sein könnte.

.Net Compact Framework: ImageButton ??

Nach langer Funkstille zum Thema Anwendungsentwicklung für Windows Mobile mit dem .Net Compact Framework (CF), möchte ich heute nochmals einen Zwischenbericht abgeben.

Mein Fazit bisher: das CF ist wirklich auf das Nötigste reduziert, fast schon um zu viele Dinge reduziert, wenn man von dem vollen Umfang des normalen Frameworks verwöhnt ist. Weniger Umfang hat wohl nur noch das .Net Micro Framework… Erste Erfahrungen durfte ich ja bereits mit dem OpenFileDialog sammeln, nun habe ich weitere Lücken gefunden, die ich gerade am Schließen bin. So ist es bspw. bei einem Button im CF nicht möglich ein Bild neben einem Label zu platzieren; das normale Framework bietet hier ein Image Property am Button an. Was also tun ? Richtig, neben der Entwicklung der Dialoge zur Erledigung einfachster Ordner- bzw. Dateiauswahloperationen habe ich begonnen eine eigene Controls-Library zu bauen. Diese beinhaltet bisher zwar nur eine Klasse „ImageButton“ (s. Bild), aber das kann ja noch wachsen.

ImageButton

ImageButton

Bzgl. der SimpleFileRequesterDialogs ist der Stand der, dass der Ordnerauswahldialog (DirectoryChooserDialog) funktioniert (s. Bild) und ich nun an dem OpenFileDialog arbeite. Aus dieser Arbeit heraus entstand auch die Notwendigkeit die eigene Controls-Library zu schreiben.

Verzeichnisauswahldialog

Verzeichnisauswahldialog

Alles in allem komme ich aus Zeitgründen nur langsam voran, aber es geht stetig weiter 😉

Windows Mobile – PhoneEventNotifier Status

Die Entwicklung des PhoneEventNotifier schreitet voran 🙂 Folgende Fähigkeiten hat das Programm bis dato:

  • Registrierung am System Event PhoneMissedCall (und somit automatischer Start der Anwendung bei Auftreten des Events)
  • Anzeige der Rufnummer des zuletzt verpassten Anrufs

Als nächstes ist geplant:

  • dem Einstellungs-Tab Leben einzuhauchen
  • Auswahl und Abspielen von Sounds

Es wird also so langsam und es macht wirklich Spaß 😉

Hier noch die vorangegangen Artikel zu diesem Thema:

Entwickeln für Windows Mobile – Fortschrittsbericht

Nach einer kleineren Pause möchte ich heute kurz ein Update zum Stand der Entwicklung einer Windows Mobile Applikation geben. Nach längerem Zaudern habe ich mich dazu entschlossen die Applikation für Windows Mobile 5 und höher auszulegen, da dass Windows Mobile 5 SDk bereits anständige Benachrichtigungs-Mechanismen mitbringt. Diese lassen sich ganz einfach mittels der im WM 5 SDK enthaltenen Managed DLLs einbinden. Benötigt werden die Namespaces Microsoft.WindowsMobile sowie Microsoft.WindowsMobile.Status. Damit kann man dann schon eine ganze Menge machen, u.a. kann man sich so auf einen verpassten Anruf-Event registrieren (PhoneMissedCall).

Die Oberfläche ist soweit entworfen, die Registrierung der Events ist auch funktionsfähig. Erste Tests sind auch bereits erfolgreich verlaufen, so zeigte das Programm in seiner Logausgabe an: „verpasster Anruf: +49xxxxxxxxxxx“ (die Zahlen wurden bewusst durch x ersetzt). Hier noch zwei Screenshots der Anwendung im Emulator:

Ansonsten gab es doch einige Anlaufschwierigkeiten, so muss man leider sagen, dass man ab einem gewissen Grad nicht um Microsofts Visual Studio herumkommt, da hier die Integration von Deployment und Device Emulator einfach runder wirkt als mit SharpDevelop o.ä. Oder etwas anders formuliert: Microsoft hat seine SDK Installer Files derart mit Voraussetzungen gepflastert (Visual Studio, ActiveSync, …), dass man wohl erst die Chance hat die Installation durchzuführen, wenn man den Orca MSI Editor von Microsoft zum patchen dieser Installer Dateien nutzt. So wollte ich zum Beispiel auf meiner virtuellen Maschine nicht unbedingt ActiveSync installieren (man müllt ja nicht sein Produktiv-System zu 😉 ), also wurde ein Patch der „Windows Mobile 5.0 Pocket PC SDK.msi“ Installer Datei fällig, dass es ActiveSync nicht zwingend erfordert etc. Irgendwann hatte ich dann aber keine Lust mehr die Steine aus dem Weg zu räumen, die Microsoft bereit legt…

Dies nun nur als kleiner Appetit-Anreger und als Zeichen dafür, dass es voran geht. Sobald die erste lauffähige Version fertig wird, werde ich diese hier veröffentlichen.

Idee zur Windows Mobile Applikation

Es gibt Neuigkeiten an der Entwicklungsfront mit dem Compact Framework 2.0 SP 1 und SharpDevelop. Anfangs sträubte sich SharpDevelop noch etwas das Compact Framework zu erkennen, aus irgendeinem Grund hat es sich dann aber nach diversen Versuchen und Forenbesuchen anders entschieden. Genau sagen, woran es lag, kann ich nicht. Ich denke, dass es an der Installationsreihenfolge liegt.

Man sollte zuerst die CompactFramework Runtimes installieren, danach das Windows Mobile 6 SDK und im Anschluß die gewünschten SDKs für das jeweilige Framework.

Achtung: Wenn man sich auf die Suche nach dem CompactFramework SDK begibt, wird man viele Treffer finden. Es sei hier aber gesagt, dass man das CompactFramework SDK mit den „normalen“ SDKs bekommt. So wird bei der Installation des .Net 2.0 SDK auch das zugehörige CompactFramework SDK auf die Platte kopiert.

Die erste kleine Demo-Applikation (klassisch >Hello World< im Fenster) war in 2 Minuten mit .Net 2.0 geschrieben. Ältere Versionen von Windows Mobile müssen zuerst mit dem .Net Framework in der richtigen Version versorgt werden (Deployment über ActiveSync), Windows Mobile 6 bringt aber bereits alles mit.

Was ist nun die Idee für meine erste Anwendung unter Windows Mobile ? Sie nennt sich „PhoneEventNotifier“ und soll die akustische Signalisierung eines verpassten Ereignisses übernehmen. Der XDA comet signalisiert ein solches Ereignis über eine Status-LED oben am Gerät, diese blinkt dann rot. Dies soll nun noch durch eine Software unterstützt werden, die einen einstellbaren Ton in einem einstellbaren Intervall wiedergibt. So machte das nämlich mein Motorola V3i (habe ich übrigens verkauft mittlerweile) – auch wenn ansonsten recht wenig innovativ war – meiner Meinung nach. An diese Art der Benachrichtigung hatte ich mich im Laufe der zwei Jahre, in denen ich das V3i hatte, gewöhnt und vermisse diese Funktionalität nun etwas bei meinem comet.

Wie soll die Software nun aussehen ? Nun, sie soll im natürlich Hintergrund laufen und mittels eines Timers gesteuert werden. Es soll natürlich immer nur auf ein einziges verpasstes Ereignis reagiert werden, nicht dass sich verpasste Ereignisse kumulieren und das Gerät zig-Mal in verschiedenen Intervallen akustische Signale ausgibt. Ebenso soll eine Zeitspanne einstellbar sein, in der das Gerät keine Signale ausgeben soll (quiet period), bspw. nachts. Die Einstellungen sollen ganz unspektakulär in einem kleinen Fenster (Tab) im Programm vorgenommen werden können.

Ansonsten reift die Idee und ich hoffe, dass ich bald erste Ergebnisse respektive Screenshots liefern kann (Hauptproblem ist wie immer die Zeit für so etwas zu erübrigen 🙁 ). Ich halte die geneigten Leser natürlich auf dem Laufenden 😉

Akkulaufzeit XDA comet / Anwendungsentwicklung [Update]

Generell möchte ich noch sagen, dass es natürlich stark von der Dauer eines Telefonats, von WLAN oder anderen Schnittstellen abhängt, wie lange das XDA comet durchhalten kann. Ich persönlich bin nicht der Dauertelefonierer, wobei ein Gespräch durchaus einmal 30-45 Minuten dauern kann. Das ist aber eher die Ausnahme. Zusätzlich schalte ich immer alle Schnittstellen ab, die ich nicht brauche (etwa WLAN und Bluetooth).

Wer das natürlich nicht macht bzw. längere Telefonate führt, wird meinen bisherigen Rekord von 6 Tagen nicht erreichen. Also betrachtet meine Aussagen bitte realistisch und mit Augenmaß. Es ist lediglich ein Wert, was machbar ist, wenn man gewisse Dinge berücksichtigt 😉

Gestern habe ich übrigens mein erstes Programm auf dem comet zum Laufen gebracht 😀 Es ist zwar nur ein einfaches „Hello World“, aber für 2 Minuten Arbeit ist es ausreichend 😉 Details folgen noch…