Van iCloud bug naar nieuwe iPhone

Door Gerco op zaterdag 4 augustus 2012 01:50 - Reacties (2)
Categorie: -, Views: 5.126

TL;DR versie: Voor niets nieuwe iPhone gekregen door totaal ongerelateerd probleem, yay!

Ik woon in de VS, we hebben hier AT&T en Apple stores met genius bars.

Een paar dagen terug kreeg ik een iPhone 4s op de werkbank die al maanden lang batterijproblemen had. Hij was binnen een uur of 4-6 leeg en sinds een paar dagen verbruikte het ding ook ongelofelijke hoeveelheden data (400MB/dag) terwijl de gebruiker hem gewoon op de tafel had liggen en niet aanraakte. Dit dataverbruik viel pas op toen de gebruiker thuis tijdelijk geen Wifi meer had door een verhuizing.

Na AT&T gebeld te hebben en hun instructies te hebben opgevolgd over het uitzetten van diagnostic reports, ophalen van email, afsluiten van background apps en het opnieuw aanmaken van iCloud en email accounts hebben we het ding eens een dag laten liggen en helemaal niets mee gedaan. Gevolg: ruwweg 300MB data verstookt, dat was het dus niet.

Volgende stap: We hangen het ding aan een mac met XCode en gaan eens naar de Console kijken. Daar staan wat interessante entries in:

code:
1
2
3
4
Aug  2 14:53:20 unknown dataaccessd[52] <Notice>: xxxxxx|CardDAV|Error|Yikes: failedToFinishInitialSync:error: https://xxxx.xxxxxxx%40xxxxx.xx@p05-contacts.icloud.com/999999999/carddavhome/card/ Error Domain=CoreDAVErrorDomain Code=7 "The operation couldn&#8217;-t -b-e -c-o-m-p-l-e-t-e-d-. -(-C-o-r-e-D-A-V-E-r-r-o-r-D-o-m-a-i-n -e-r-r-o-r -7-.-)-"
Aug  2 14:53:20 unknown wifid[28] <Error>: WiFi:[xxxxxxxxx.xxxxxxx]: Client dataaccessd set type to background application
Aug  2 14:53:22 unknown dataaccessd[52] <Notice>: xxxxxx|CardDAV|Error|Yikes: failedToFinishInitialSync:error: https://xxxx.xxxxxxx%40xxxxx.xx@p05-contacts.icloud.com/999999999/carddavhome/card/ Error Domain=CoreDAVErrorDomain Code=7 "The operation couldn&#8217;-t -b-e -c-o-m-p-l-e-t-e-d-. -(-C-o-r-e-D-A-V-E-r-r-o-r-D-o-m-a-i-n -e-r-r-o-r -7-.-)-"
Aug  2 14:53:22 unknown wifid[28] <Error>: WiFi:[xxxxxxxxx.xxxxxxx]: Client dataaccessd set type to background application



Deze logregels herhaalden zich elke paar seconden. Er gaat overduidelijk iets mis met de iCloud sync, maar wat? iCloud uitzetten hielp, maar is natuurlijk niet echt een oplossing. iCloud account opnieuw instellen hielp niet en zelfs de telefoon compleet restoren had geen enkele zin. Op naar de genius bar!

Aangekomen bij de dichtsbijzijnde Apple store vragen we de lokale genius om naar het probleem te kijken. De genius hoort me even aan en controleert het serienummer van de iPhone. Zonder te aarzelen (en zonder naar het probleem te kijken) pakt de beste man een splinternieuwe iPhone 4s en begint de omruilprocedure. Bij navraag weet hij ook niet wat het probleem is maar hij is er zeker van dat een nieuwe telefoon het wel zal oplossen, wie ben ik om daar tegenin te gaan?

Een nieuwe iPhone later stellen we de iCloud account van de gebruiker in en alles werkt prima! Helaas blijkt na verdere inspectie dat maar enkele tientallen van de 386 contacten op de telefoon zijn aangekomen. Iets verder kijkend zien we dat de ~340 ontbrekende contacten ook niet op iCloud staan. De genius zet de contacten op de old-skool manier over vanaf de oude telefoon en we wachten even tot de telefoon alles gesynced heeft.

Tot onze grote verbazing synchroniseert de nieuwe iPhone slechts 20 contacten met iCloud en vervalt daarna direct in de lus uit de bovenstaande logs. Er is dus iets speciaals met de contacten aan de hand waar iCloud zich in verslikt. Dit zorgt voor een oneindige synchronisatie lus die de batterij leegzuigt en massaal data verbruikt!

Wat blijkt nu: De contacten op deze telefoon zijn ooit eens (door diezelfde Apple store) vanaf een Windows Mobile (HTC Diamond) telefoon naar de iPhone gekopieerd en er stonden een berg notities met Russische tekst bij. Die notities zijn tijdens dat proces corrupt geraakt en iCloud verslikt zich daar blijkbaar nogal in. Na het verwijderen van alle corrupte notities synchroniseert de telefoon prima en werkt alles naar behoren, met dien verstande dat de gebruiker wel met een nieuwe iPhone de winkel uitloopt terwijl er met de oorspronkelijke telefoon helemaal niets mis was.

Wie we moeten bedanken voor de nieuwe telefoon is niet helemaal duidelijk, maar bedankt Apple/Microsoft/HTC!

Google Guice and plugins en

By Gerco on Wednesday 27 June 2012 19:00 - Comments are closed
Category: -, Views: 5.494

While refactoring an application to use Google Guice for dependency injection, I ran across some challenges on how to modularize my application with plugins. It turns out that these is a relatively simple solution: Guice's Multibinders.

Lets look at the problem first. Guice favors constructor injection and that often results in big, ugly constructors with dozens of arguments. In my experience this mostly happens when constructing GUI containers with a lot of "static" items (menus, tabs, lists of configuration pages, etc). These lists of items are not truly static because we would like to be able to extend them through plugins, for example.

When we follow a naive approach, a constructor for a JFrame that holds a bunch of tabs may look like this:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Inject
public MainFrame(
    Panel1 p1, Panel2 p2, Panel3 p3, Panel4 p4,
    Panel5 p5, Panel6 p6, Panel7 p7, Panel8 p8)
{
    addTab(p1);
    addTab(p2);
    addTab(p3);
    addTab(p4);
    addTab(p5);
    addTab(p6);
    addTab(p7);
    addTab(p8);
}



This has the advantage that it's perfectly clear which tabs this frame will host and in which order they will appear. Aside from that, it would be easy to add some code to listen to application events and enable and disable specific tabs when required. This code does lack a few things though: It's a lot of work to add tabs to it and it doesn't allow for adding more tabs after the application has been distributed (plugins).

To allow for adding tabs we need to solve several problems:
  • Allow for addition of tabs
  • Allow tab order to be determined by plugins or the user
  • Provide some way for tabs to enable/disable based on application state
Lets start one at a time and first make the list of tabs dynamic from the point of view of the frame that will host them:

Java:
1
2
3
4
5
6
7
8
@Inject
public MainFrame(Set<JComponent> panels)
{
    for(JComponent panel: panels)
    {
        addTab(panel);
    }
}



Now we are not injecting each tab separately, but we inject instead a Set of tabs. This removes the requirement for the frame to know exactly which tabs exist and makes the code somewhat simpler. We still have to specify which tabs go in this frame though. This is done in the Guice Module:


Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class UIModule extends AbstractModule {

    @Override
    protected void configure() {
        Multibinder<JComponent> panels = Multibinder.newSetBinder(binder(), JComponent.class);
        panels.addBinding().to(Panel1.class);
        panels.addBinding().to(Panel2.class);
        panels.addBinding().to(Panel3.class);
        panels.addBinding().to(Panel4.class);
        panels.addBinding().to(Panel5.class);
        panels.addBinding().to(Panel6.class);
        panels.addBinding().to(Panel7.class);
        panels.addBinding().to(Panel8.class);
    }
}



So what has really changed? We moved the list of panels from one piece of Java code to another piece of Java code. It's still Java code and this didn't help one bit to implement a plugin architecture.

This is where the multi-module aspect of the Multibinder comes in. When a different Guice module defines a binder for the same type (in this case Set<JComponent>), they will be merged. At runtime, there will only be one Set<JComponent> and all tabs from all Modules will be presented in the frame.

Set<JComponent> is a little to generic of a type to be using for this purpose though. We want to do more with this. We need (at a minimum) to specify a name and a way to get a reference to the actual JComponent so lets start by defining an interface:

Java:
1
2
3
4
public interface UITab {
    public String getUITabName();
    public JComponent getUITabComponent();
}


This interface defines a few methods we'll need to display our tabs. "getUITabName" should return the display name for the tab and "getUITabComponent" is expected to return a reference to the actual UI component.

Each Panel class can now implement this interface, like so:

Java:
1
2
3
4
5
6
7
8
9
public class Panel1 extends JPanel implements UITab {
    public String getUITabName() {
        return "Panel 1";
    }

    public JComponent getUITabComponent() {
        return this;
    }
}



Each Panel can now be defined in its own module like this:

Java:
1
2
3
4
5
6
7
public class Panel1Module extends AbstractModule {
    @Override
    protected void configure() {
        Multibinder<UITab> panels = Multibinder.newSetBinder(binder(), UITab.class);
        panels.addBinding().to(Panel1.class);
    }
}



Now that each of the panels is defined in its own module, we can split them out into separate projects (plugins). Each Panel can get its own jar file. All we still need is a way for the main application to detect the available plugins and load them. The ServiceLoader class is a good possibility. Some classpath detection of an appliction specific plugin descriptor or an XML file listing all installed plugins are also possible.

Programmers: What we do

Door Gerco op dinsdag 14 februari 2012 02:06 - Reacties (4)
Categorie: -, Views: 7.198

Er is momenteel een "what x thinks I do" meme gaande dus ik dacht ook maar eens wat bij te dragen:

Programmer

Altitude developers add offline mode en

By Gerco on Sunday 13 June 2010 12:21 - Comments are closed
Category: -, Views: 2.813

In a previous blog post I ranted about the required connection to the login server before being able to play Altitude (cartoony planes, mayhem, etc). The connection requirement is still there, but the developers have added an offline mode to be able to play Altitude against bots when you don't have an internet connection available.

While the whole universe of Altitude players are still kicked out of their games whenever the central login server fails (including LAN players), this hasn't happened since the Steam free weekend is over so the servers seem to be capable of handling the load at the moment.

I'd like to thank the Altitude team for this update, great way to listen to your players!

Little brother

Door Gerco op zaterdag 29 mei 2010 13:20 - Reacties (13)
Categorie: -, Views: 2.946

Met de verkiezingen voor de deur was ik wat aan het rondgooglen over anti-privacy, OV-chipkaarten en andere enge maatregelen en kwam ik gisteren het boek "Little Brother" van Cory Doctorow tegen.

Cory biedt dit boek gratis aan als eBook in diverse formaten (onder Creative Commons) en het is ook als hardcopy te koop. De ongeduldige Nederlander in mij heeft de ePub versie gedownload en het boek in 1 ruk uitgelezen. Het is 04.30 geworden vannacht, maar het was het waard. De hardcopy is inmiddels onderweg naar mijn brievenbus.

Little Brother beschrijft een toekomst die niet al te ver weg is. Sterker nog, deze staat al voor de deur en staat op het punt om aan te bellen. Na een terroristische aanslag in San Fransico veranderd de stad in een politiestaat. Chipkaarten als de FasTrak (lees OV-chipkaart) worden door de Department of Homeland Security (DHS) gebruikt om alle verplaatsingen (zowel per OV als auto) te registreren en plukken iedereen van de straat die niet aan het "normale" patroon voldoet. Overal zijn camera's, zogenaamd voor de veiligheid, maar niemand kan uitleggen hoe die camera's de burger dan precies veiliger maken.

Het boek heeft een sterke technologische ondertoon en de hoofdpersoon is een echte tweaker. Na onterecht gearresteerd te worden en in een geheime gevangenis aan een dagenlange ondervraging blootgesteld te zijn besluit hij zelf de DHS aan te pakken. Het verhaal is fictie, maar de technologie die erin voorkomt is dat (bijna) niet. Het is een eye-opener voor iedereen die dacht dat hij niets te verbergen had.

Download gratis als eBook of voor mensen die niet graag van een scherm lezen kun je de hardcopy kopen bij bol.com.