Georg fährt extra nach Berlin um Steve Ballmer zu treffen

31 Tage Mango | Tag #7: Rohdaten der Kamera

Die­ser Arti­kel ist Tag #7 der Serie 31 Tage Man­go von Jeff Blankenburg.

Der Ori­gi­nal­ar­ti­kel befin­det sich hier: Day #7: Raw Came­ra Data.

Heu­te beschäf­ti­gen wir uns mit der Kame­ra der Win­dows Pho­nes und wie wir die­se in unse­ren eige­nen Anwen­dun­gen ver­wen­den kön­nen. Es geht dabei aller­dings nicht um Laun­chers und Choo­sers. Die­se haben wir in 31 Days of Win­dows Pho­ne am Tag 7 und 8 behan­delt. Zur Erin­ne­rung: die­se Aktio­nen erlau­ben es Ihnen, den Benut­zer zur Auf­nah­me bzw. zur Aus­wahl eines Foto aus der Samm­lung auf­zu­for­dern. Heu­te wol­len wir uns damit befas­sen, wie man die Roh­da­ten der Kame­ra anzeigt, wie man ein Bild aus den Roh­da­ten auf­nimmt, wie man die Hard­ware But­tons benutzt und wie man ein Foto auf dem Tele­fon des Benut­zers abspei­chern kann.

Falls Sie die fer­ti­ge Anwen­dung die­ses Arti­kels her­un­ter­la­den möch­ten, fin­den Sie die­se auch im Win­dows Pho­ne Marketplace.

Wenn ich von Roh­da­ten der Kame­ra rede, mei­ne ich das Live-Bild der Kame­ra und wie man die­ses direkt in der Anwen­dung ver­wen­det. Am bes­ten lässt sich das wie­der an einem klei­nen Video zeigen:

Jetzt, da Sie wis­sen, wor­um es heu­te gehen wird, begin­nen wir mit etwas Quellcode.

Das Kamerabild anzeigen

Der ers­te Schritt bei unse­rer Kame­ra-Anwen­dung wird sein, das Live-Bild der Kame­ra anzu­zei­gen. Die­se Schritt ist zum Glück sehr ein­fach. Wir erstel­len ein Rec­tang­le Con­trol in unse­rer XAML Sei­te und set­zen die Source die­ses Rec­tan­gles auf ein neu­es Pho­to­Ca­me­ra Objekt in unse­rer C# Datei. Unse­re XAML Sei­te sieht damit so aus:

<phone:PhoneApplicationPage
   x:Class="Day7_RawCamera.MainPage"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
   FontFamily="{StaticResource PhoneFontFamilyNormal}"
   FontSize="{StaticResource PhoneFontSizeNormal}"
   Foreground="{StaticResource PhoneForegroundBrush}"
   SupportedOrientations="Portrait" Orientation="Portrait"
   shell:SystemTray.IsVisible="True"> 

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
 
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="31 DAYS OF MANGO" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="raw camera" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>
 
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Rectangle x:Name="ViewBox" Height="460" Margin="-22,-1,-131,148">
                <Rectangle.Fill>
                    <VideoBrush x:Name="CameraSource" />
                </Rectangle.Fill>
                <Rectangle.RenderTransform>
                    <RotateTransform Angle="90" CenterX="240" CenterY="240" />
                </Rectangle.RenderTransform>
            </Rectangle>
        </Grid>
    </Grid>
</phone:PhoneApplicationPage>

Wie Sie im XAML oben sehen, habe ich der Stan­dard­sei­ten­vor­la­ge ein Rec­tang­le hin­zu­ge­fügt. Den Wert der Fill Eigen­schaft habe ich auf einen Video­Brush mit dem Namen „Came­ra­Sour­ce“ gesetzt. Sie soll­ten eben­falls das Ren­der­Trans­form Ele­ment beach­ten, wel­ches ich auf das Rec­tang­le ange­wen­det habe. Indem wir es um 90 Grad dre­hen, tra­gen wir der Tat­sa­che Rech­nung, dass die Kame­ra im Tele­fon in Land­scape Ori­en­tie­rung ver­baut ist. Im C# code-behind müs­sen wir nun die Kame­ra­da­ten dem Video­Brush zuwei­sen. Das machen wir, indem wir ein neu­es Pho­to­Ca­me­ra Objekt mit den Namen „came­ra“ erstel­len. Die Source des Video­Brush Objekts set­zen wir auf die­se PhotoCamera.

using System; 
using System.Windows; 
using Microsoft.Phone.Controls; 
using Microsoft.Devices; 
using System.Windows.Media.Imaging; 
using System.Windows.Media; 

namespace Day7_RawCamera 
{ 
   public partialclass MainPage : PhoneApplicationPage
   { 
      PhotoCamera camera; 

      // Constructor
      public MainPage() 
      { 
         InitializeComponent(); 
      } 

      protectedoverride void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
      { 
         base.OnNavigatedTo(e); 

         if (PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing)) 
            camera = new PhotoCamera(CameraType.FrontFacing); 
         else
            camera = new PhotoCamera(CameraType.Primary); 
         CameraSource.SetSource(camera); 
      } 

      protectedoverride void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e) 
      { 
         if (camera != null) 
         { 
            camera.Dispose(); 
         } 
      } 
   } 
} 

Wie ich bereits erwähnt habe, ist das alles ver­gleichs­wei­se ein­fach. Es gibt den­noch ein paar wich­ti­ge Fein­hei­ten zu beach­ten. Im Code oben wer­den Sie fest­ge­stellt haben, dass ich bei der Erstel­lung des Pho­to­Ca­me­ra Objekts die Para­me­ter CameraType.Primary und CameraType.FrontFacing ver­wen­det habe. Dadurch gebe ich an, dass ich ent­we­der die Stan­dard­ka­me­ra auf Rück­sei­te des Tele­fons oder die nach vor­ne gerich­te­te Kame­ra ver­wen­den möch­te. Gerä­te, die nach dem Start von Man­go erschie­nen sind, haben optio­nal eine nach vor­ne gerich­te­te Kame­ra. In die­sem Bei­spiel ver­wen­den wir vor­zugs­wei­se die nach vor­ne gerich­te­te Kame­ra. Nur wenn die­se nicht ver­füg­bar ist, ver­wen­den wir die Standardkamera.

Sie wer­den fest­ge­stellt haben, dass ich die OnNa­vi­gated­To und OnNa­vi­ga­ting­From Hand­ler über­schrie­ben habe. Jedes Mal, wenn der Benut­zer zur Sei­te navi­giert (egal ob inner­halb der App oder indem er bei­spiels­wei­se von einer ande­ren Anwen­dung zurück­kehrt), soll sicher­ge­stellt wer­den, dass die Kame­ra initia­li­siert wird. Die OnNa­vi­ga­ting­From Metho­de ver­wen­den wir, um die Kame­ra frei­zu­ge­ben, wenn der Benut­zer die Sei­te ver­lässt. Dadurch spa­ren wir sowohl Akku als auch Haupt­spei­cher. Zum ver­ant­wor­tungs­vol­len Umgang mit der Kame­ra gehört deren Frei­ga­be, wenn wir sie nicht mehr brauchen.

Wir sind jetzt soweit, dass Sie die Anwen­dung aus­pro­bie­ren kön­nen. Wenn Sie die Anwen­dung auf einem ech­ten Win­dows Pho­ne Gerät aus­pro­bie­ren, wer­den Sie das sehen, was auch die Kame­ra sieht, so wie im Video oben. Wenn Sie die Anwen­dung im Emu­la­tor lau­fen las­sen, wer­den Sie etwa fol­gen­des sehen:

Der Emu­la­tor kann lei­der nicht auf eine Web­cam oder ande­re Video­quel­len zugrei­fen. Statt des­sen zeigt er eine wei­ße Flä­che für das Kame­ra­bild. Zudem kreist eine klei­ne schwar­ze Flä­che um den Bild­schirm. Wenn wir hier­von ein Bild auf­neh­men, bekom­men wir genau den wei­ßen Hin­ter­grund mit der klei­nen schwar­zen Flä­che. Las­sen Sie uns das ausprobieren:

Ein Bild aufnehmen

Im nächs­ten Schritt wol­len wir unse­re Kame­ra­an­wen­dung so erwei­tern, dass der Anwen­der damit ein Bild auf­neh­men kann. Hier­zu fügen wir der Benut­zer­ober­flä­che erst mal einen But­ton hinzu.

<Button Foreground="Green" BorderBrush="Green" Content="Capture" Height="72" HorizontalAlignment="Left" Margin="6,535,0,0" Name="CaptureButton" VerticalAlignment="Top" Width="160" Click="CaptureButton_Click" />

Ich habe den But­ton grün gemacht da er vor dem Kame­ra­bild dar­ge­stellt wird. Wenn Sie den Emu­la­tor benut­zen, wer­den Sie den But­ton vor dem wei­ßen Hin­ter­grund sonst nicht sehen. Wir haben auch gleich eine Metho­de für den Click Event ange­ge­ben. Dar­in wol­len wir das Tele­fon ver­an­las­sen, ein Bild aufzunehmen.

Jetzt müs­sen wir ein paar Metho­den in der code-behind Datei schrei­ben. Zunächst schrei­ben wir die Event Hand­ler Metho­de für den But­ton Click Event. Sie ent­hält eigent­lich nur eine Zei­le — da die Auf­nah­me eines Fotos eine auf­wän­di­ge Ope­ra­ti­on ist, müs­sen wir aller­dings sicher­stel­len, dass jede Auf­nah­me abge­schlos­sen ist bevor die nächs­te beginnt. In unse­rem Bei­spiel habe ich ein­fach einen try/catch Block um den Auf­ruf gesetzt um dar­aus resul­tie­ren­de Feh­ler zu vermeiden.

private void CaptureButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
   try { camera.CaptureImage(); }
   catch (Exception ex) { MessageBox.Show(ex.Message); }
} 

Die ent­schei­den­de Zei­le ist der Auf­ruf von camera.CaptureImage(). Sie kön­nen ja pro­bie­ren, was pas­siert, wenn Sie nur die­se Zei­le ver­wen­den und die But­ton öfter hin­ter­ein­an­der drü­cken. Die Anwen­dung wird abstürzen. 

Mit der Cap­tu­reImage() Metho­de sagen wir der Kame­ra nur, dass sie jetzt ein Bild auf­neh­men soll. Wenn wir kei­nen Event Hand­ler erstel­len, der das Resul­tat emp­fängt, wer­den wir das Ergeb­nis nie bekom­men. Hier­zu ver­wen­den wir den Cap­tu­reIm­age­Available Event unse­res Pho­to­Ca­me­ra Objekts.

Damit sie den gan­zen Code in Ihre eige­ne Datei kopie­ren kön­nen, habe ich unten die kom­plet­te code-behind Datei ein­ge­fügt. Die wich­ti­gen Stel­len sind der neue Event Hand­ler in unse­rer OnNa­vi­gated­To Metho­de, der camera_CaptureImageAvailable Event Hand­ler und die Metho­de Thread­Sa­feIm­age­Cap­tu­re, wel­che letzt­end­lich das Ergeb­nis unse­rer Auf­nah­me emp­fängt. Beach­ten Sie auch, dass wir alle Event Hand­ler in der Metho­de OnNa­vi­ga­ted­From wie­der von den ent­spre­chen­den Ereig­nis­sen lösen. Damit spa­ren wir Spei­cher und Akku­lauf­zeit, wenn die Anwen­dung im Hin­ter­grund wartet.

using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Devices;
using System.Windows.Media.Imaging;
using System.Windows.Media;

namespace Day7_RawCamera
{
   public partial class MainPage : PhoneApplicationPage
   {
      PhotoCamera camera;

      // Constructor
      public MainPage()
      {
         InitializeComponent();
      }

      protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
      {
         base.OnNavigatedTo(e);

         if (PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing))
            camera = new PhotoCamera(CameraType.FrontFacing);
         else
            camera = new PhotoCamera(CameraType.Primary);
         camera.CaptureImageAvailable += new System.EventHandler<ContentReadyEventArgs>(camera_CaptureImageAvailable);
         CameraSource.SetSource(camera);
      }

      protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
      {
         if (camera != null)
         {
            camera.Dispose();
            camera.CaptureImageAvailable -= camera_CaptureImageAvailable;
         }
      }

      private void CaptureButton_Click(object sender, System.Windows.RoutedEventArgs e)
      {
         try { camera.CaptureImage(); }
         catch (Exception ex) { Dispatcher.BeginInvoke(() => MessageBox.Show(ex.Message)); }
      }

      void camera_CaptureImageAvailable(object sender, ContentReadyEventArgs e)
      {
         Dispatcher.BeginInvoke(() => ThreadSafeImageCapture(e));
      }

      void ThreadSafeImageCapture(ContentReadyEventArgs e)
      {
         BitmapImage image = new BitmapImage();
         image.SetSource(e.ImageStream);
         ImageBrush still = new ImageBrush();
         still.ImageSource = image;
         ViewBox.Fill = still;
      }
   }
} 

Wie Sie in der Metho­de Thread­Sa­feIm­age­Cap­tu­re sehen, erstel­len wir ein neu­es Bit­ma­pI­mage Objekt (wel­ches ein using System.Windows.Media.Imaging State­ment ganz oben benö­tigt) und set­zen die Source die­ses Bit­ma­pI­mage auf das Ergeb­nis unse­rer Aufnahme.

Die rest­li­chen Schrit­te in der Metho­de erset­zen den Video­Brush, den wir zur Anzei­ge der Roh­da­ten ver­wen­det haben, um das gera­de auf­ge­nom­me­ne Stand­bild anzuzeigen.

Das ist schon mal ein guter Anfang für eine Kame­ra­an­wen­dung. Es gibt aber noch wesent­lich mehr zu wis­sen rund um die Kame­ra, wie zum Bei­spiel Ver­wen­dung des Hard­ware But­tons der Kame­ra (den jedes Win­dows Pho­ne ent­hält) oder wie man ein auf­ge­nom­me­nes Bild in den Eige­nen Auf­nah­men ablegt — also an der Stel­le, an der auch die nor­ma­le Kame­ra App ihre Fotos speichert.

Den Hardware Button der Kamera benutzen

Der Kame­ra Hard­ware But­ton feu­ert drei ver­schie­de­ne Events: Shut­ter­Key­Half­Press, Shut­ter­Key­Pres­sed und Shut­ter­Key­Re­leased. Wenn wir unse­re eige­ne Kame­ra­an­wen­dung bau­en, hat der But­ton kein Stan­dard­ver­hal­ten — das müs­sen wir sel­ber bau­en. Da die Anwen­der höchst­wahr­schein­lich ver­traut sind mit dem Ver­hal­ten des Kame­ra­but­tons soll­te sich unse­re Anwen­dung bei den drei Events erwar­tungs­ge­mäß verhalten:

  • Shut­ter­Key­Half­Press — durch die­se Akti­on fokus­siert die Kamera.
  • Shut­ter­Key­Press — durch die­se Akti­on soll­te ein Bild auf­ge­nom­men werden.
  • Shut­ter­Key­Re­leased — durch die­ses Ereig­nis wis­sen wir, dass nichts mehr zu tun ist. Ins­be­son­de­re kön­nen wir das Fokus­sie­ren einstellen.

Als ers­tes wer­den wir die drei Ereig­nis­se imple­men­tie­ren. Im fol­gen­den Code­bei­spiel fin­det sich nur die Imple­men­tie­rung von OnNa­vi­gated­To — die Event Hand­ler für die ein­zel­nen Ereig­nis­se bau­en wir danach.

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
   base.OnNavigatedTo(e);

   if (PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing))
      camera = new PhotoCamera(CameraType.FrontFacing);
   else
      camera = new PhotoCamera(CameraType.Primary);
   camera.CaptureImageAvailable += new System.EventHandler<ContentReadyEventArgs>(camera_CaptureImageAvailable);
   CameraSource.SetSource(camera);

   CameraButtons.ShutterKeyHalfPressed += new EventHandler(CameraButtons_ShutterKeyHalfPressed);
   CameraButtons.ShutterKeyPressed += new EventHandler(CameraButtons_ShutterKeyPressed);
   CameraButtons.ShutterKeyReleased += new EventHandler(CameraButtons_ShutterKeyReleased);
} 

Als ers­te Event Hand­ler Metho­de bau­en wir die für den Shut­ter­Key­Half­Pres­sed Event, da sie die auf­wän­digs­te ist (obwohl sie nicht wirk­lich auf­wän­dig ist). Zunächst über­prü­fen wir, dass unser Pho­to­Ca­me­ra Objekt vor­han­den ist, dann ver­su­chen wir, die Kame­ra zu fokus­sie­ren. Ich habe den Auf­ruf in einen try/catch Block ein­ge­schlos­sen, da wir Focus() nicht auf­ru­fen kön­nen, wenn die Kame­ra gera­de eine Auf­nah­me macht. Eine even­tu­ell auf­tre­ten­de Excep­ti­on igno­rie­ren wir ein­fach. Die Excep­ti­on wird jedes Mal flie­gen, wenn Sie eine Auf­nah­me machen, da der But­ton auf dem Weg zum „Pres­sed“ Zustand zwei Mal den „Half-Pres­sed“ Zustand durch­läuft. Ein­mal auf dem Weg „nach unten“ und ein­mal, wenn er wie­der los­ge­las­sen wird. Wenn Sie die­sen Feh­ler in eine Log­da­tei schrei­ben wol­len, nur zu. Für die­ses Bei­spiel habe ich den catch-Block ein­fach leer gelassen.

void CameraButtons_ShutterKeyHalfPressed(object sender, EventArgs e)
{
   if (camera != null)
   {
      try { camera.Focus(); }
      catch (Exception ex) { }
   }
} 

Für den Shut­ter­Key­Pres­sed Event ver­wen­de ich den Code von vor­hin, als ich den But­ton zur Auf­nah­me eines Bil­des erstellt habe.

void CameraButtons_ShutterKeyPressed(object sender, EventArgs e)
{
   if (camera != null)
   {
      try { camera.CaptureImage(); }
      catch (Exception ex) { Dispatcher.BeginInvoke(() => MessageBox.Show(ex.Message)); }
   }
} 

Zu guter Letzt haben wir noch den Shut­ter­Key­Re­leased Event. In unse­rem Fall müs­sen wir nur dafür sor­gen, dass wir nicht wei­ter fokus­sie­ren. Can­cel­Fo­cus() ist die Metho­de, mit der die Kame­ra das Fokus­sie­ren abbricht.

void CameraButtons_ShutterKeyReleased(object sender, EventArgs e)
{
   if (camera != null)
      camera.CancelFocus();
} 

Zum Schluss stel­len wir noch sicher, dass die Event Hand­ler wie­der ent­fernt wer­den, wenn wir die Sei­te ver­las­sen. Wie schon beim Cap­tu­reIm­age­Available Event machen wir das in der Metho­de OnNa­vi­ga­ting­From. Ich habe hier den kom­plet­ten Code der Metho­de dar­ge­stellt. Neu sind aber nur die unte­ren drei Zeilen.

protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
{
   if (camera != null)
   {
      camera.Dispose();
      camera.CaptureImageAvailable -= camera_CaptureImageAvailable;
      CameraButtons.ShutterKeyHalfPressed -= CameraButtons_ShutterKeyHalfPressed;
      CameraButtons.ShutterKeyPressed -= CameraButtons_ShutterKeyPressed;
      CameraButtons.ShutterKeyReleased -= CameraButtons_ShutterKeyReleased;
   }
} 

Bilder in Eigene Aufnahmen abspeichern

Hier­für hat Micro­soft eine Media­Li­bra­ry Klas­se erstellt. Wir wer­den spä­ter in die­ser Serie eine gan­ze Anwen­dung zur Ver­wen­dung der Media­Li­bra­ry bau­en — jetzt wol­len wir sie nur benut­zen, um unse­re Auf­nah­me in den Eige­nen Auf­nah­men abzu­le­gen. Dadurch kann der Anwen­der die Fotos unse­rer Anwen­dung genau so ver­wal­ten wie alle ande­ren Fotos auf dem Telefon.

Der gesam­te Pro­zess erfolgt in genau zwei Zei­len Code, wobei die ers­te Zei­le nur dar­in besteht, eine Refe­renz auf die Media­Li­bra­ry zu erhal­ten. Ganz oben in der Sei­te, dort wo wir auch das Pho­to­Ca­me­ra Objekt erstellt haben, fügen wir die­se Zei­le hinzu.

MediaLibrary library = new MediaLibrary(); 

Das war der ers­te Schritt. Im zwei­ten Schritt schau­en wir uns noch mal die Metho­de Thread­Sa­feIm­age­Cap­tu­re an. Im bis­he­ri­gen Code haben wir die Auf­nah­me gemacht, die Eigen­schaft Fill von Rec­tang­le geän­dert und sie auf unse­re Auf­nah­me gesetzt. Für die­ses Bei­spiel enfer­nen wir den gesam­ten Metho­den­rumpf und erset­zen ihn mit:

void ThreadSafeImageCapture(ContentReadyEventArgs e)
{
   library.SavePictureToCameraRoll(DateTime.Now.ToString() + ".jpg", e.ImageStream);
}

Auf einem ech­ten Win­dows Pho­ne soll­ten Sie jetzt in der Lage sein, ein Foto auf­zu­neh­men. Die­ses soll­ten Sie im Tele­fon im Bil­der Hub unter Eige­ne Auf­nah­men wie­der fin­den. Hier ist noch mal ein klei­nes Video um zu illus­trie­ren, wor­um es geht:

Das war’s im Wesent­li­chen zur Kame­ra! Es gibt natür­lich vie­le wei­te­re Din­ge, die man mit den Roh­da­ten der Kame­ra anstel­len kann, z.B. Vide­os auf­neh­men, Mani­pu­la­ti­on des auf­ge­nom­me­nen Fotos, Ände­rung der Blitz-Ein­stel­lun­gen usw. Es gibt eine sehr gute Tuto­ri­al­se­rie bei der Code Samples for Win­dows Pho­ne Sei­te auf MSDN und Sie fin­den eini­ge Bei­spie­le hier.

Zusammenfassung

Im wahr­schein­lich längs­ten Arti­kel der Serie haben Sie gelernt, wie man die Roh­da­ten der Kame­ra anzeigt, wie man eine Benut­zer­ober­flä­che zur Auf­nah­me eines Bil­des erstellt, wie man den Kame­ra Hard­ware But­ton dazu ver­wen­den kann und wie man Fotos in Eige­ne Auf­nah­men spei­chern kann.

Wenn Sie eine kom­plett lauf­fä­hi­ge Win­dows Pho­ne Solu­ti­on mit dem gan­zen Bei­spiel­code die­ses Arti­kels her­un­ter­la­den möch­ten, kli­cken Sie auf den Down­load Code Button.

Mor­gen wer­den wir kom­plett die Rich­tung ändern und uns einen Teil der Nut­zer­da­ten auf dem Tele­fon anse­hen. Genau­er gesagt wer­den wir uns mor­gen mit den Kon­tak­ten des Benut­zers befassen.

Bis dahin!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert