MantisDroid and MantisDroid Free has been updated to version 1.2.
New functions and changes:
v.1.2 - Full version
-Manage project versions: create, read, update and delete.
v.1.2 - Both versions
-View custom fields for issues.
-Http Basic Authentication supported.
-Https support for non standard ports (443 is the standard port).
-Speed improvement for authorization.
-QR code scan supports query parameters "port" (handling ports), "authuser" (username for http basic authentication) and "authpw" (password for http basic authentication).
Download from Play Store:
MantisDroid - https://play.google.com/store/apps/details?id=se.nextsource.android.mantisdroid
MantisDroid Free - https://play.google.com/store/apps/details?id=se.nextsource.android.mantisdroidfree
2012-12-01
2012-11-13
Obfuskera Androidapp
Den Androidapp jag ska obfuskera är MantisDroid och den består av ett library (MantisDroidLibrary) och 2 appar: en gratisversion (MantisDroid Free) och en betalversion (MantisDroid).
Jag använder ProGuard för obfuskering och optimering. Det verktyget följer med Android SDK:n.
Jag använder ProGuard för obfuskering och optimering. Det verktyget följer med Android SDK:n.
Först måste konfigurationsfilerna för ProGuard rättas till. I foldern <android-sdk>/tools/proguard/ ska filerna proguard-android.txt och proguard-android-optimize.txt editeras:
#-keep public class com.google.vending.licensing.ILicensingService
#-keep public class com.android.vending.licensing.ILicensingService
Dvs. kommentera bort de 2 raderna eftersom de annars ger fel i obfuskeringen.
Jag använder Ant för att bygga mina projekt så om du inte redan gjort det så kör följande kommando i din projektkatalog:
android update project -p .
Den skapar upp bland annat build.xml och lite andra filer som behövs.
Börja med projektet MantisDroidLibrary.
Den ska inte obfuskeras i sitt projekt utan gör det när apparna byggs och obfuskeras.
Se till att obfuskering inte är aktiverad genom att titta i project.properties och verifiera att direktivet proguard.config inte är aktiverad.
De två apparna har precis samma inställningar så gör samma sak i båda.
Öppna project.properties och kommentera fram följande för endast obfuskering:
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
Om du vill ha både obfuskering och optimering så lägg till följande:
proguard.config=${sdk.dir}/tools/proguard/proguard-android-optimize.txt:proguard-project.txt
I filen proguard-project.txt i projekt så ska nu projektspecifika regler läggas till. Skapa filen om den inte redan finns.
I min skriver jag:
-dontwarn org.xmlpull.v1.**
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
-keep public class com.google.android.vending.licensing.ILicensingService
Den första regeln döljer alla varningar för klasser i paketet org.xmlpull.v1. Det gör jag eftersom det blir krockar mellan klasser i android.jar och ett library (ksoap2-android) som jag använder. I mitt fall är det ingen fara utan helt ok.
Den andra regeln är en optimeringsregel som ser till att optimera bort alla anrop till Log.d(...) och Log.v(...). Anledningen till det är att de loggningarna inte ska komma ut i mina apk:er eftersom de avslöjar vad olika delar av min kod gör. Samtidigt så ska inte debug- och verbose-loggning finnas ute i kundernas installationer.
Den tredje regeln är för att jag använder Google Play Licensing och inte vill att den ska optimeras bort.
För att signeringen ska fungera så behöver man fylla i key.store och key.alias i filen ant.properties:
key.store=mantisdroid_release_key.keystore
key.alias=mantisdroid
key.alias.password=[your_password]
key.store.password=[your_password]
key.alias.password=[your_password]
key.store.password=[your_password]
Library-projektet behöver inte signeras så skriv inte någon key.store eller key.alias där.
Kompilera, obfuskera, optimera och signera sedan appen med Ant genom att köra (i projektets folder):
ant release
2012-11-07
MantisDroid v.1.1.1
MantisDroid har nu också uppdaterats till v.1.1.1.
Buggfix-release med samma ändringar som för MantisDroid Free:
-Development versions of MantisBT can now be used.
-QR codes now support other ports than port 80.
Anledningen till att den inte släpptes samtidigt som gratisversionen var för att projekthanteringen inte fungerade som den skulle. Det gick inte att skapa eller spara projekt. Orsaken till det var att ksoap2-android inte lyckades serialisera ArrayList. Vector går däremot bra. Förhoppningsvis går det att använda ArrayList i version 3.0 av ksoap2-android som dock endast har release candidates ute.
Ladda hem från Play Store: MantisDroid
2012-11-06
MantisDroid Free v.1.1.1
MantisDroid Free har uppdaterats till v.1.1.1.
Buggfix-release med följande ändringar:
-Development versions of MantisBT can now be used.
-QR codes now support other ports than port 80.
Ladda hem från Play Store: MantisDroid Free
MantisDroid (full version) will be updated to v.1.1.1 soon. Testing is not finished yet.
Buggfix-release med följande ändringar:
-Development versions of MantisBT can now be used.
-QR codes now support other ports than port 80.
Ladda hem från Play Store: MantisDroid Free
MantisDroid (full version) will be updated to v.1.1.1 soon. Testing is not finished yet.
2012-11-02
Dekompilering av Android-appar
Först och främst skriver jag det här för att belysa den problematik som finns när det gäller apputveckling och hur lätt det är att kopiera appar och kringgå olika typer av skydd. Det är inte tänkt att vara en tutorial för hur man piratkopierar appar.
För att förhindra otillåten kopiering och användande av en app så går det att aktivera Google Play Licensing. Hur man implementerar det är upp till varje utvecklare, men lämpligt är att appen då och då kontrollerar mot Google Play om appen är installerad på korrekt sätt, dvs. genom Google Play och att eventuella avgifter är betalda. Om Google Play svarar att appen inte är licensierad så ber man användaren att köpa appen.
Problemet är att det ganska lätt går att dekompilera appen och ta bort licensieringskontrollen och sedan använda appen helt fritt.
Hur gör man det?
Skaffa först verktygen. Installera/packa upp på lämplig plats.
dex2jar: http://code.google.com/p/dex2jar/ - Läser dex-filer och skapar jar-filer.
JD-GUI: http://java.decompiler.free.fr/?q=jdgui - Grafiskt verktyg för att visa innehållet i .class-filer.
På Ubuntu kör jag följande kommando för att få ut en jar av en apk:
d2j-dex2jar.sh android-app.apk
Resultatet ut från den är filen android-app.jar
Starta JD-GUI och öppna android-app.jar.
Voila! All kod i klartext!
Härifrån är det lätt att ändra på det man behöver för att till exempel ta bort licensiering eller aktivera olika funktioner. Packa slutligen ihop appen och signera den. Sen är den klar att användas igen.
Hur gör man för att skydda sig från det här? Svaret heter obfuskering. Det gör koden väldigt mycket svårare att läsa eftersom de flesta namn översätts till enstaka bokstäver.
Här kan ni läsa om hur man obfuskerar med hjälp av ProGuard:
http://developer.android.com/tools/help/proguard.html
Obfuskering ger ett bra skydd, men ha ändå för vana att gå igenom den obfuskerade koden med JD-GUI och kontrollera känsliga punkter i koden och se till att det inte är för uppenbart vad som händer och hur man kan kringgå det. Alla klasser och metoder byter inte namn så det kan gå att luska ut hur det fungerar.
Det är viktigt att se till att loggning inte avslöjar vad som händer.
Ett enkelt och snabbt sätt är att låta ProGuard ta bort alla anrop till Log.d och Log.v med följande direktiv (observera att optimization måste vara påslagen):
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
Slutsats
Om du vill skydda din app så lägg in Google Play Licensing och obfuskera sedan all kod. Det viktigaste skyddet är ändå att du är medveten om problematiken och hur enkelt det är att titta i din kod, så kolla själv innan någon annan gör det.
För att förhindra otillåten kopiering och användande av en app så går det att aktivera Google Play Licensing. Hur man implementerar det är upp till varje utvecklare, men lämpligt är att appen då och då kontrollerar mot Google Play om appen är installerad på korrekt sätt, dvs. genom Google Play och att eventuella avgifter är betalda. Om Google Play svarar att appen inte är licensierad så ber man användaren att köpa appen.
Problemet är att det ganska lätt går att dekompilera appen och ta bort licensieringskontrollen och sedan använda appen helt fritt.
Hur gör man det?
Skaffa först verktygen. Installera/packa upp på lämplig plats.
dex2jar: http://code.google.com/p/dex2jar/ - Läser dex-filer och skapar jar-filer.
JD-GUI: http://java.decompiler.free.fr/?q=jdgui - Grafiskt verktyg för att visa innehållet i .class-filer.
På Ubuntu kör jag följande kommando för att få ut en jar av en apk:
d2j-dex2jar.sh android-app.apk
Resultatet ut från den är filen android-app.jar
Starta JD-GUI och öppna android-app.jar.
Voila! All kod i klartext!
Härifrån är det lätt att ändra på det man behöver för att till exempel ta bort licensiering eller aktivera olika funktioner. Packa slutligen ihop appen och signera den. Sen är den klar att användas igen.
Hur gör man för att skydda sig från det här? Svaret heter obfuskering. Det gör koden väldigt mycket svårare att läsa eftersom de flesta namn översätts till enstaka bokstäver.
Här kan ni läsa om hur man obfuskerar med hjälp av ProGuard:
http://developer.android.com/tools/help/proguard.html
Obfuskering ger ett bra skydd, men ha ändå för vana att gå igenom den obfuskerade koden med JD-GUI och kontrollera känsliga punkter i koden och se till att det inte är för uppenbart vad som händer och hur man kan kringgå det. Alla klasser och metoder byter inte namn så det kan gå att luska ut hur det fungerar.
Det är viktigt att se till att loggning inte avslöjar vad som händer.
Ett enkelt och snabbt sätt är att låta ProGuard ta bort alla anrop till Log.d och Log.v med följande direktiv (observera att optimization måste vara påslagen):
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
Slutsats
Om du vill skydda din app så lägg in Google Play Licensing och obfuskera sedan all kod. Det viktigaste skyddet är ändå att du är medveten om problematiken och hur enkelt det är att titta i din kod, så kolla själv innan någon annan gör det.
2012-10-30
MantisDroid v.1.1
MantisDroid och MantisDroid Free har uppdaterats till v.1.1.
Feature-release med följande ändringar:
-Subproject support implemented.
-Icons in dashboard have better sizes on large screens.
-Button to start QR code scan added to login screen.
-Support for ordinary http/https links added for scanned QR codes.
-View status of project is now displayed in project list.
-New icons to save and cancel report issue and create project. The floppy/diskette icon is now put to the past.
-MantisDroid Free got a new launcher icon to make it different from the full version.
Ladda hem från Play Store: MantisDroid och MantisDroid Free.
Feature-release med följande ändringar:
-Subproject support implemented.
-Icons in dashboard have better sizes on large screens.
-Button to start QR code scan added to login screen.
-Support for ordinary http/https links added for scanned QR codes.
-View status of project is now displayed in project list.
-New icons to save and cancel report issue and create project. The floppy/diskette icon is now put to the past.
-MantisDroid Free got a new launcher icon to make it different from the full version.
Ladda hem från Play Store: MantisDroid och MantisDroid Free.
2012-10-11
MantisDroid v.1.0.2
MantisDroid och MantisDroid Free har uppdaterats till v.1.0.2.
Buggfix-release med följande ändringar:
-Fixed issue with Touchwiz on SGS3.
-New icons that support all screen sizes.
-Improved error message in login screen.
-Input fields in the login screen is no longer cleared while switching between apps.
-App size is smaller by moving out not used images.
Ladda hem från Play Store: MantisDroid
Buggfix-release med följande ändringar:
-Fixed issue with Touchwiz on SGS3.
-New icons that support all screen sizes.
-Improved error message in login screen.
-Input fields in the login screen is no longer cleared while switching between apps.
-App size is smaller by moving out not used images.
Ladda hem från Play Store: MantisDroid
2012-09-29
MantisDroid Free lanserad på Play Store
Det finns nu en gratisversion av MantisDroid på Play Store.
De funktioner som saknas i gratisversionen är:
De funktioner som saknas i gratisversionen är:
- Ändring av issues
- Hanteringen av projekt.
Utöver det så är det exakt samma app.
Gratis- och betalapp med samma kodbas
Jag har efter lanseringen av MantisDroid insett att jag även behöver publicera en gratisversion, så att man kan ladda hem appen och se om den är något att ha innan man betalar för fullversionen. Visst, man har 15 minuter på sig att testa en betalapp, men det är inte många som gör det eftersom 15 minuter är så väldigt kort tid.
Lösningen är alltså att skapa en gratisversion av min app med begränsad funktionalitet.
Hur gör man en gratisversion utan att duplicera all kod?
Det är faktiskt ganska enkelt. En app kan använda en annan app och referera till den som ett library (bibliotek). På så sätt kan den nya appen utnyttja allt i den andra. Dock kan inte en app som markerats som library längre vara en app som går att installera på en enhet. Därför behövs det 3 projekt: En betalapp, en gratisapp och en library-app. I mitt fall så ligger all kod i betalappen som redan är publicerad på Play Store.
- Skapa library-appen genom att skapa ett nytt projekt med lämpligt paketnamn, ex. se.nextsource.android.mantisdroid
Det är samma paketnamn som i betalappen, men det gör ingenting. - Öppna library-appen i Eclipse, ta fram properties för projektet, klicka på Android och markera checkboxen "Is Library".
- Flytta kod och resurser som ska vara gemensamma från betalappen till library-appen.
- Öppna properties för betalappen, klicka på Android och lägg till library-appen som ett Library.
- Skapa gratisappen som ett nytt projekt med nytt paketnamn, ex. se.nextsource.android.mantisdroidfree
- Öppna properties för gratisappen, klicka på Android och lägg till library-appen som ett Library.
- Deklarera de komponententer (activity, service, receiver, provider etc. och även permissions, uses-library etc.) som gratis- och betalappen använder från library-appen.
- Nu har du 2 appar med exakt samma kodbas men med olika paketnamn.
- För att särskilja versionerna mellan varandra så jag lagt till en ny Application-klass i gratis- och betalapp-projekten som ärver från en Application-klassen som ligger i library-appen. Vid onCreate så sätts vilken version som körs i superklassen och sedan anropas super.onCreate(). I superklassens onCreate så slår jag av och på olika funktioner som ska skilja applikationerna åt.
Ref: http://developer.android.com/tools/projects/projects-eclipse.html
Problem jag stötte på
-Se till att ingen duplicering av kod eller res-filer finns för då bygger det inte!
-Från SDK 14 så går det inte att använda resId i switch-case i ett library eftersom de inte längre är final så ändra det med refactor-funktionen i Eclipse till if-else. Irriterande, men det finns en bra förklaring:
http://android-developers.blogspot.se/2011/10/changes-to-library-projects-in-android.html
-Proguard fick svårt att obfuskera koden i biblioteket så jag var tvungen att lägga till följande i proguard.cfg:
-keep public class com.google.android.vending.licensing.ILicensingService
-dontwarn org.xmlpull.v1.**
-dontwarn android.support.**
Obs! Tänk på att lägga till det i alla 3 proguard.cfg.
Resultatet
Nu när allt är klart så behöver jag bara göra följande för att införa kodändringar, bygga och publicera mina 2 appar:
Problem jag stötte på
-Se till att ingen duplicering av kod eller res-filer finns för då bygger det inte!
-Från SDK 14 så går det inte att använda resId i switch-case i ett library eftersom de inte längre är final så ändra det med refactor-funktionen i Eclipse till if-else. Irriterande, men det finns en bra förklaring:
http://android-developers.blogspot.se/2011/10/changes-to-library-projects-in-android.html
-Proguard fick svårt att obfuskera koden i biblioteket så jag var tvungen att lägga till följande i proguard.cfg:
-keep public class com.google.android.vending.licensing.ILicensingService
-dontwarn org.xmlpull.v1.**
-dontwarn android.support.**
Obs! Tänk på att lägga till det i alla 3 proguard.cfg.
Resultatet
Nu när allt är klart så behöver jag bara göra följande för att införa kodändringar, bygga och publicera mina 2 appar:
- Gör ändringar och fixar i library-appen.
- Ändra versionsnumret i apparna så att de stegas upp.
- Kör kommandot: ant release på båda apparna så att de bygger, obfuskeras och signeras för release.
- Testkör båda apparna så att de fungerar och ändringarna är testade.
- Lägg upp de 2 nya apk:erna på Play Store.
- Klart!
2012-09-06
Google Play Price Calculator
När jag lanserade min första betalapp på Play Store i helgen så funderade jag lite hur jag skulle sätta mina priser när vissa länder har 0% i moms och andra har 25%.
Det jag kom fram till var att jag ville att slutkund skulle "belastas" lika mycket oberoende av momsen så därför räknade jag fram så att det blev samma summa i alla länder.
Exempel:
I Sverige kostar appen 12 kr + moms = 15 kr
I Australien blev 12 kr = 1.74 AUD vilket om man konverterar tillbaks blir 12 kr eftersom det inte är någon moms på köpen där. För att "belasta" slutkund med 15 kr även i Australien så måste man höja priset till 2.2 AUD vilket blir 15.19 kr.
Det blev ett evigt räknande fram och tillbaks och lösningen på det problemet är så klart att låta datorn göra jobbet.
Här är min lösning:
http://www.nextsource.se/service/android/google_play_price_calculator/
Den fungerar som tjänsten i utvecklarkonsollen på Play Store och använder Googles valutakonverterare och gör mängder med AJAX-anrop mot den. Ett anrop för varje konvertering. Det jag lagt till är att den gör en extra konvertering tillbaks till SEK så att man ser hur mycket slutkund "belastas". Det går också att ändra värdet i varje valuta och direkt se vad det blir i SEK.
Mitt verktyg är bara ett hjälpmedel för att enkelt se ungefär hur mycket det belastar plånboken i varje land. Man bör så klart även ta hänsyn till vilken betalningsförmåga invånarna har i landet och kanske sänka priset i länder där lönenivån ligger lägre, men också höja i de länder där man i genomsnitt tjänar bättre.
Det jag kom fram till var att jag ville att slutkund skulle "belastas" lika mycket oberoende av momsen så därför räknade jag fram så att det blev samma summa i alla länder.
Exempel:
I Sverige kostar appen 12 kr + moms = 15 kr
I Australien blev 12 kr = 1.74 AUD vilket om man konverterar tillbaks blir 12 kr eftersom det inte är någon moms på köpen där. För att "belasta" slutkund med 15 kr även i Australien så måste man höja priset till 2.2 AUD vilket blir 15.19 kr.
Det blev ett evigt räknande fram och tillbaks och lösningen på det problemet är så klart att låta datorn göra jobbet.
Här är min lösning:
http://www.nextsource.se/service/android/google_play_price_calculator/
Den fungerar som tjänsten i utvecklarkonsollen på Play Store och använder Googles valutakonverterare och gör mängder med AJAX-anrop mot den. Ett anrop för varje konvertering. Det jag lagt till är att den gör en extra konvertering tillbaks till SEK så att man ser hur mycket slutkund "belastas". Det går också att ändra värdet i varje valuta och direkt se vad det blir i SEK.
Mitt verktyg är bara ett hjälpmedel för att enkelt se ungefär hur mycket det belastar plånboken i varje land. Man bör så klart även ta hänsyn till vilken betalningsförmåga invånarna har i landet och kanske sänka priset i länder där lönenivån ligger lägre, men också höja i de länder där man i genomsnitt tjänar bättre.
2012-09-02
MantisDroid lanserad på Play Store
En Android-klient för MantisBT.
Målet har varit att klienten ska kunna göra det mesta som går att göra via webbklienten och det målet är nått. Självklart kommer det mer i senare versioner, men version 1.0 är riktigt kraftfull.
The following features and functions are implemented:
- List issues for all projects or a specified project.
- View issues lists - assigned to me, unassigned, all issues, recently modified, reported by me and resolved.
- Create, read, edit and delete issue.
- Full notes handling.
- Full attachments handling.
- Shortcut issue functions - Add Note, Change Status To, Assign To, Upload File.
- Search issue by Id.
- List all projects.
- Create, read, edit and delete projects (managers and administrators).
Det finns några begränsningar:
- Minst Android 4.0
- MantisBT 1.2.9 eller högre
Det finns även en kul specialfunktion som gör att man kan logga in med hjälp av en URL som lämpligast görs till en QR-kod. Formatet är:
mantisdroid://path_to_mantisbt?user=usernam&pw=password&usessl=1
(user, pw och usessl är valfria).
(user, pw och usessl är valfria).
Ladda hem och testa. Den kostar endast 15 kr inkl. moms.
2012-05-21
Problem med View Swiping och orientation changes
Jag har byggt en app med View Swiping enligt den här artikeln. Jag har gjort några ändringar för att det ska passa min app.
Min implementation:
En FragmentActivity som har en ViewPager.
ViewPager har en FragmentPagerAdapter.
I FragmentPagerAdapter så skapas det upp 6 stycken ListFragment.
Varje ListFragment har en ArrayAdapter som ska hålla sina Items.
Jag lägger till Items till varje adapter beroende på vilken status ett item har med:
fragmentPagerAdapter.getItem(listIndex).getAdapter ().add(item);
Det fungerar galant första gången jag visar mina listfragment.
Problemet:
När jag vrider på telefonen så skapas allt om via onDestroy() och onCreate() som det ska, men mina listfragment blir tomma. Jag har skapat om dem så det borde bli samma sak som första gången jag laddar allt.
Felet beror på att Android återanvänder listfragmenten som skapades första gången och de är inte samma som jag lägger till mina items till. Därför blir listorna tomma.
Jag använder getItem() för att få tag i mitt listfragment, men det gör inte Android. Den anropar inte ens getItem() andra gången utan letar reda på dem via instantiateItem().
Min lösning:
Lösningen känns lite som ett hack, men fungerar väldigt bra (det skapas dock upp några extra fragment, men det är nog inte jätteofta som användarna kommer att vrida telefonen fram och tillbaks just i listvyn där det här används):
Gör en override på: public Object instantiateItem(ViewGroup container, int position) i FragmentPagerAdapter:
Kod:
@Override
public Object instantiateItem(ViewGroup container, int position) {
ItemsFragment fragment = (ItemsFragment) super.instantiateItem(container, position);
if(fragment.getAdapter() == null) {
ItemsFragment myFragment = getItem(position);
fragment.setListAdapter(myFragment.getAdapter());
fragment.setTitle(myFragment.getTitle());
}
return fragment;
}
Notera: Mitt ItemsFragment har en ny metod getAdapter() som returnerar en typad adapter "ItemListAdapter" och nya metoder för set och getTitle() som används för att få rätt texter på PagerTitleStrip i ViewPagern.
Jag använder min metod getAdapter() för att kolla om det funna fragmentet har en adapter. Om den inte har det så tar jag en adapter via metoden getItem() som returnerar fragments som jag har kontroll på.
Ni kanske undrar varför jag helt enkelt inte bara lägger till:
android:configChanges= "orientation|keyboardHidden|screenSize"
i manifestet. För det första så ska den tekniken undvikas eftersom det gör hanteringen av resources onödigt komplicerad. Vidare så hanteras inte ActionBar och PagerTitleStrip korrekt.
Nästa steg nu är att använda:
onRetainCustomNonConfigurationInstance/getLastCustomNonConfigurationInstance
för att slippa ladda om all data mellan vridningarna av telefonen.
Ref: Mitt inlägg på Swedroid
2012-05-13
Automatiserad testning av Android-appar
Jag har den här veckan lagt in Robotium som testverktyg för den Android-app, MantisDroid, som jag håller på och utvecklar. Med hjälp av Robotium så kan jag sätta upp helt automatiserade tester av hela appen som kan köras både på emulator och riktig device. Jag har även byggt in stöd för att samtidigt testa mot flera olika versioner av MantisBT (en buggtracker som hanterar defekter för projekt) som är den servertjänst min app går mot.
Robotium är ett testverktyg som kör tester mot användargränssnittet på en app som kör på antingen en emulator eller riktig device. Den simulerar klick på knappar och andra GUI-kontroller, text-hantering i textboxar, den verifierar att olika kontrollera och texter hittas m.m. Kolla på videon ovan för att få en snabb introduktion i hur det fungerar.
Jag har byggt upp mina tester i en klass för varje typ av test, dvs. en klass som hanterar Login-hantering, en för Project och en för Issues.För att hantera flera olika versioner av MantisBT har jag skapat en Enum (MantisBTUrlEnum) som håller i URL:erna för de olika versionerna. Varje testfall loopar över alla värden i Enum:en och plockar ut den URL som ska testas och kör testet mot den. Det är alltså viktigt att återställa miljön efter varje körning så att nästa loop har samma förutsättningar som varvet innan. Om jag varit testpuritan så skulle jag kanske skapat ett testfall för varje version, men jag tycker att även bland testfallen så ska duplicering av kod undvikas. En idé som slog mig nu var att bryta ut själva testet i en egen metod och sedan låta varje testfall anropa den metoden med den URL som ska testas. Nu kommer jag dock att behålla min implementation för den fungerar bra och för tillfället har jag bara en enda URL att testa mot. När det blir fler URL:er så kanske jag bryter isär testfallen om det är fördelaktigt på något sätt.
Tips:
Använd inte hårdkodade strängar. Om ni gör det så kommer testerna att fallera om en sträng ändras eller om ni lägger till fler språk. Använd istället: solo.getString(id);
Ex.
För att hämta strängen "Login" så skriver ni:
solo.getString(se.nextsource.android.mantisdroid.R.string.login);
För att hämta "OK" som ligger inbyggt i Android så skriver ni:
solo.getString(android.R.string.ok);
Jag har stött på följande problem:
Problem - returnerar fel aktivitet vid uppstart:
I setUp() vill jag kontrollera att jag är på rätt aktivitet, men solo.getCurrentActivity() ger fel aktivitet som svar. Den returnerar den aktivitet som angetts vid uppstart. I min applikation anger jag LoginActivity som startaktivitet, men om användaren redan är inloggad så flyttas den automatiskt till MainActivity. Robotium har inte koll på det.
Lösning:
Lägg en sökning efter en textsträng som finns på den aktivitet du önskar starta med i en while-loop. I mitt fall är det en knapp med texten "Login". Loopa tills den strängen hittas. Inuti while-loopen så kontrollerar jag om jag är på MainActivity genom att söka efter en viss textsträng där och om den hittas så tar jag upp menyn och klickar på "Logout":
solo.clickOnMenuItem("Logout"));
I alla andra fall så trycker jag på back-knappen:
solo.goBack();
Problem - hittar inte knappar när soft keyboard är synligt:
När man klickar på en EditTextPreference i en PreferenceActivity så får man på en verklig device upp soft keyboard eftersom textfältet får fokus automatiskt. När soft keyboard är uppe så går det inte att klicka på "OK"-knappen. Knappen hittas med solo.searchButton("OK"); men är inte klickbar. På emulatorn inträffar inte det här eftersom soft keyboard inte kommer fram. Det saknas metoder i Robotium för att kontrollera om soft keyboard är framme eller inte.
Lösning:
Skapa en metod som stänger soft keyboard och använd den då soft keyboard automatiskt poppar upp:
@SuppressWarnings("static-access")
private void closeSoftKeyboard() {
InputMethodManager imm = (InputMethodManager)getActivity().
getSystemService(getActivity().INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(solo.getEditText(0).getWindowToken(), 0);
}
Problem - kan inte klicka på knappar i ActionBar:
Robotium saknar stöd för att klicka på knappar i ActionBar.
Lösning:
Använd Instrumentation och id:et för knappen för att klicka på den:
getInstrumentation().invokeMenuActionSync(solo.getCurrentActivity(), se.nextsource.android. mantisdroid.R.id.menu_settings, 0);
Robotium är ett testverktyg som kör tester mot användargränssnittet på en app som kör på antingen en emulator eller riktig device. Den simulerar klick på knappar och andra GUI-kontroller, text-hantering i textboxar, den verifierar att olika kontrollera och texter hittas m.m. Kolla på videon ovan för att få en snabb introduktion i hur det fungerar.
Jag har byggt upp mina tester i en klass för varje typ av test, dvs. en klass som hanterar Login-hantering, en för Project och en för Issues.För att hantera flera olika versioner av MantisBT har jag skapat en Enum (MantisBTUrlEnum) som håller i URL:erna för de olika versionerna. Varje testfall loopar över alla värden i Enum:en och plockar ut den URL som ska testas och kör testet mot den. Det är alltså viktigt att återställa miljön efter varje körning så att nästa loop har samma förutsättningar som varvet innan. Om jag varit testpuritan så skulle jag kanske skapat ett testfall för varje version, men jag tycker att även bland testfallen så ska duplicering av kod undvikas. En idé som slog mig nu var att bryta ut själva testet i en egen metod och sedan låta varje testfall anropa den metoden med den URL som ska testas. Nu kommer jag dock att behålla min implementation för den fungerar bra och för tillfället har jag bara en enda URL att testa mot. När det blir fler URL:er så kanske jag bryter isär testfallen om det är fördelaktigt på något sätt.
Tips:
Använd inte hårdkodade strängar. Om ni gör det så kommer testerna att fallera om en sträng ändras eller om ni lägger till fler språk. Använd istället: solo.getString(id);
Ex.
För att hämta strängen "Login" så skriver ni:
solo.getString(se.nextsource.android.mantisdroid.R.string.login);
För att hämta "OK" som ligger inbyggt i Android så skriver ni:
solo.getString(android.R.string.ok);
Jag har stött på följande problem:
Problem - returnerar fel aktivitet vid uppstart:
I setUp() vill jag kontrollera att jag är på rätt aktivitet, men solo.getCurrentActivity() ger fel aktivitet som svar. Den returnerar den aktivitet som angetts vid uppstart. I min applikation anger jag LoginActivity som startaktivitet, men om användaren redan är inloggad så flyttas den automatiskt till MainActivity. Robotium har inte koll på det.
Lösning:
Lägg en sökning efter en textsträng som finns på den aktivitet du önskar starta med i en while-loop. I mitt fall är det en knapp med texten "Login". Loopa tills den strängen hittas. Inuti while-loopen så kontrollerar jag om jag är på MainActivity genom att söka efter en viss textsträng där och om den hittas så tar jag upp menyn och klickar på "Logout":
solo.clickOnMenuItem("Logout"));
I alla andra fall så trycker jag på back-knappen:
solo.goBack();
Problem - hittar inte knappar när soft keyboard är synligt:
När man klickar på en EditTextPreference i en PreferenceActivity så får man på en verklig device upp soft keyboard eftersom textfältet får fokus automatiskt. När soft keyboard är uppe så går det inte att klicka på "OK"-knappen. Knappen hittas med solo.searchButton("OK"); men är inte klickbar. På emulatorn inträffar inte det här eftersom soft keyboard inte kommer fram. Det saknas metoder i Robotium för att kontrollera om soft keyboard är framme eller inte.
Lösning:
Skapa en metod som stänger soft keyboard och använd den då soft keyboard automatiskt poppar upp:
@SuppressWarnings("static-access")
private void closeSoftKeyboard() {
InputMethodManager imm = (InputMethodManager)getActivity().
getSystemService(getActivity().INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(solo.getEditText(0).getWindowToken(), 0);
}
Problem - kan inte klicka på knappar i ActionBar:
Robotium saknar stöd för att klicka på knappar i ActionBar.
Lösning:
Använd Instrumentation och id:et för knappen för att klicka på den:
getInstrumentation().invokeMenuActionSync(solo.getCurrentActivity(), se.nextsource.android. mantisdroid.R.id.menu_settings, 0);
2012-05-02
NFC-taggar
Igår kom jag på att jag ville använda NFC för att slå av och på framför allt Wi-Fi och blåtand. Sedan dess har jag hållt på och kollat på olika taggar och olika appar för att hantera det. Jag fastnade för Xperia SmartTags, men fick inte appen med Widgeten att funka i min Nexus S. Troligtvis köper jag nog SmartTags ändå eftersom man får 4 snygga taggar för 120 kr + frakt (hos Dustin). Droidstuffs taggar var inte så snygga...tyvärr. Skaffa snyggare taggar så köper jag dem därifrån direkt! :-)
Idag fick jag tips om pluginen Locale NFC Plugin som fungerar ihop med Tasker som jag köpt för länge sedan. Nu kan jag använda RFID-taggen i mitt Västtrafikkort till att slå av Wi-Fi och blåtand, sätta ned ljusstyrkan och höja ringsignalen till max.
Fördelen med Locale NFC Plugin är att den funkar med alla taggar, inkl. de icke skrivbara.
Om någon undrar så gjorde jag så här:
1. Öppna Tasker och gå till fliken Tasks
2. Skapa nytt Task och döp till lämpligt namn "NFC Out"
3. Lägg till de Actions du önskar göra när Tasken körs: Wi-Fi off, BT off, Ringer Volume 7 etc.
4. Spara ditt Task
5. Gå till fliken Profiles
6. Skapa ny profil och döp till lämpligt namn "NFC Out"
7. Välj Context: State->Plugin->Locale NFC Plugin
8. Tryck Edit och håll din telefon mot taggen, tryck Ok
9. Spara och välj den Task du tidigare skapade (NFC Out)
10. Testa! Fungerar grymt bra!
2012-04-13
Omdesignad webbplats
Webbplatsen för Next Source (http://www.nextsource.se) har fått en omdesign. Fokus ligger på minimalistisk design och att presentera några av de projekt jag arbetar/arbetat med.
Samtidigt så passade jag på att följa standardarderna för HTML5, CSS2.1 och WCAG 2.0.
För att validera HTML5 och CSS2.1 så använder jag W3Cs egna validatorer.
För WCAG så använder validatorn på http://achecker.ca (där finns även validator för HTML och CSS)
För att validera HTML5 och CSS2.1 så använder jag W3Cs egna validatorer.
För WCAG så använder validatorn på http://achecker.ca (där finns även validator för HTML och CSS)
2012-03-15
Logga in på dator utan lösenord, dvs. public key authentication
För att slippa skriva in lösenord varje gång man loggar in på en dator via SSH så kan man använda en publik nyckel för att autentisera användaren.
Skapa först upp publik och privat nyckel:
$ ssh-keygen -t dsa
Följ instruktionerna och välj ett lösenord som skiljer sig från användarens lösenord
Den publika nyckeln hamnar här: /home/[user]/.ssh/id_dsa.pub
Den private nyckeln hamnar här: /home/[user]/.ssh/id_dsa
Flytta den publika nyckeln till den dator du vill logga in på:
$ scp ~/.ssh/id_dsa.pub [user]@[server]:.ssh/authorized_keys
Nu kan du logga in på den andra datorn utan att kunna lösenordet för kontot där
$ ssh [user]@[server]
$ scp [file] [user]@[server]:/[dir]
Dock måste du skriva in lösenordet till nyckelfilen varje gång.
För att slippa skriva in det lösenordet varje gång så skriver man:
$ exec /usr/bin/ssh-agent $SHELL
$ ssh-add
Klart! Nu kan du logga in utan att skriva några lösenord!
För att ändra lösenordet till nyckelfilen så skriver man:
$ ssh-keygen -f ~/.ssh/id_dsa -p
Skapa först upp publik och privat nyckel:
$ ssh-keygen -t dsa
Följ instruktionerna och välj ett lösenord som skiljer sig från användarens lösenord
Den publika nyckeln hamnar här: /home/[user]/.ssh/id_dsa.pub
Den private nyckeln hamnar här: /home/[user]/.ssh/id_dsa
Flytta den publika nyckeln till den dator du vill logga in på:
$ scp ~/.ssh/id_dsa.pub [user]@[server]:.ssh/authorized_keys
Nu kan du logga in på den andra datorn utan att kunna lösenordet för kontot där
$ ssh [user]@[server]
$ scp [file] [user]@[server]:/[dir]
Dock måste du skriva in lösenordet till nyckelfilen varje gång.
För att slippa skriva in det lösenordet varje gång så skriver man:
$ exec /usr/bin/ssh-agent $SHELL
$ ssh-add
Klart! Nu kan du logga in utan att skriva några lösenord!
För att ändra lösenordet till nyckelfilen så skriver man:
$ ssh-keygen -f ~/.ssh/id_dsa -p
2012-02-02
Blockera besökare på Blogger/Blogspot
Googles bloggverktyg Blogger/Blogspot har inte någon blockeringsfunktion för enskilda användare. Det är allt eller inget genom inställningen under Inställningar - Basfunktioner - Tillstånd - Bloggläsare. Rättighetern som finns tillgängliga är Alla, Endast bloggskribenter och Enbart de här läsarna. Det fungerar bra för bloggar man vill hålla privata till ett begränsat antal läsare, men fungerar inte alls bra när man vill blockera några få.
Går det att blockera enskilda användare även fast det saknas stöd i Blogger?
Ja, med hjälp av lite javascript och klipp och klistra så löser man det genom att blockera vissa IP-adresser eller host-namn.
Det går hyffsat lätt att ta sig förbi skyddet genom att använda en proxy, men jag tror ändå att ett skydd byggt med javascript hindrar majoriteten av de man vill slippa. En proxy kräver ändå ett antal extrasteg och ofta att man betalar för tjänsten.
Hur gör man?
Jag har hämtat inspiration från följande sidor:
http://www.javascriptkit.com/script/script2/blockip.shtml
http://stackoverflow.com/questions/102605/can-i-lookup-the-ip-address-of-a-hostname-from-javascript
Gå till Blogger (kontrollpanelen för bloggarna på Blogspot) och klicka på din blogg.
Gå till menyvalet Layout och klicka på "Lägg till Gadget".
Rulla ner till "HTML/JavaScript" och tryck på +-knappen för att lägga till den.
Skriv ingen titel utan klistra endast in följande i rutan för Innehåll:
http://pastie.org/3301106 (Klicka på länken och hämta koden från Pastie)
Ändra följande rad och fyll i de IP-adresser du vill blockera (exempel på 2 olika adresser):
var bannedIps=["23.23.23.23", "11.11.11"]
Skriptet matchar början på en IP-adress så för att blockera alla IP-adresser som börjar med 23.23.23 skriver du följande:
var bannedIps=["23.23.23"]
Det går även att matcha hostname om du kör din egen tjänst för att slå upp IP-adresser och hostname. Blockera hostname genom att ändra följande rad:
var bannedHosts=["host1.se", "host2.se"];
Tryck slutligen på Spara
Det läggs nu till en gadget som heter "HTML/Javascript" och kommer skicka alla besökare med de inmatade IP-adresserna till http://www.google.com
Om du vill ändra adress till var de skickas så ändrar du adressen i följande rad:
window.location.replace("http://www.google.com");
Vad gör skriptet?
Den börjar med att se till att det garanterat finns en funktion för att hämta ut alla element via ett klassnamn. Vissa webbläsare har inte metoden getElementsByClassName.
Sedan kommer själva blockeringsfunktionen som matchar en lista med blockerade IP-adresser mot den IP-adress som skickades till funktionen. Om den får en träff så döljer den alla div:ar som har klassen "content" och skickar sedan vidare användaren till http://www.google.com
Därefter kommer en callback-funktion som används för att ta emot svaret från tjänsten som tar fram IP-adressen. Svaret är i json så den tar ut IP-adressen ur svaret och skickar den vidare till blockeringsfunktionen.
Allra sist kommer anropet till tjänsten som kollar upp IP-adressen på besökaren och genom att ange en callback-parameter så triggar den min callback-funktion som slutligen triggar blockeringsfunktionen.
Kända problem
Tjänsten för att kolla upp IP-adresser och sedan anropa min callback-funktion blir lätt överbelastad eftersom många använder den. Det som händer är att tjänsten ligger på Google App Engine och utvecklaren kör bara gratisvarianten vilket bara tillåter ett visst antal requester per dygn. När det inträffar så kommer blockeringsfunktionen att sluta fungera tills tjänsten får ny quota.
Min lösning på det är att tillhandahålla min egen tjänst skriven i PHP. Den är inte publik och om jag släpper URL:en dit så riskerar den att bli överbelastad. Det är enkelt att skapa det själv med följande PHP-kod:
http://pastie.org/3301306 (Klicka på länken och hämta koden från Pastie)
PHP-skriptet skickar först ut headers som anger att det är en response i JSON och att inget ska cachas. Sedan plockar det ut IP-adress, hostname och eventuell callback-parameter och skriver ut det i JSON-format. Om en callback-parameter är angiven så läggs JSON-svaret som ett argument till angiven funktion. Det gör att när man bäddar in skriptet i en webbsida så kommer den automatiskt anropa callback-funktionen.
Går det att blockera enskilda användare även fast det saknas stöd i Blogger?
Ja, med hjälp av lite javascript och klipp och klistra så löser man det genom att blockera vissa IP-adresser eller host-namn.
Det går hyffsat lätt att ta sig förbi skyddet genom att använda en proxy, men jag tror ändå att ett skydd byggt med javascript hindrar majoriteten av de man vill slippa. En proxy kräver ändå ett antal extrasteg och ofta att man betalar för tjänsten.
Hur gör man?
Jag har hämtat inspiration från följande sidor:
http://www.javascriptkit.com/script/script2/blockip.shtml
http://stackoverflow.com/questions/102605/can-i-lookup-the-ip-address-of-a-hostname-from-javascript
Gå till Blogger (kontrollpanelen för bloggarna på Blogspot) och klicka på din blogg.
Gå till menyvalet Layout och klicka på "Lägg till Gadget".
Rulla ner till "HTML/JavaScript" och tryck på +-knappen för att lägga till den.
Skriv ingen titel utan klistra endast in följande i rutan för Innehåll:
http://pastie.org/3301106 (Klicka på länken och hämta koden från Pastie)
Ändra följande rad och fyll i de IP-adresser du vill blockera (exempel på 2 olika adresser):
var bannedIps=["23.23.23.23", "11.11.11"]
Skriptet matchar början på en IP-adress så för att blockera alla IP-adresser som börjar med 23.23.23 skriver du följande:
var bannedIps=["23.23.23"]
Det går även att matcha hostname om du kör din egen tjänst för att slå upp IP-adresser och hostname. Blockera hostname genom att ändra följande rad:
var bannedHosts=["host1.se", "host2.se"];
Tryck slutligen på Spara
Det läggs nu till en gadget som heter "HTML/Javascript" och kommer skicka alla besökare med de inmatade IP-adresserna till http://www.google.com
Om du vill ändra adress till var de skickas så ändrar du adressen i följande rad:
window.location.replace("http://www.google.com");
Vad gör skriptet?
Den börjar med att se till att det garanterat finns en funktion för att hämta ut alla element via ett klassnamn. Vissa webbläsare har inte metoden getElementsByClassName.
Sedan kommer själva blockeringsfunktionen som matchar en lista med blockerade IP-adresser mot den IP-adress som skickades till funktionen. Om den får en träff så döljer den alla div:ar som har klassen "content" och skickar sedan vidare användaren till http://www.google.com
Därefter kommer en callback-funktion som används för att ta emot svaret från tjänsten som tar fram IP-adressen. Svaret är i json så den tar ut IP-adressen ur svaret och skickar den vidare till blockeringsfunktionen.
Allra sist kommer anropet till tjänsten som kollar upp IP-adressen på besökaren och genom att ange en callback-parameter så triggar den min callback-funktion som slutligen triggar blockeringsfunktionen.
Kända problem
Tjänsten för att kolla upp IP-adresser och sedan anropa min callback-funktion blir lätt överbelastad eftersom många använder den. Det som händer är att tjänsten ligger på Google App Engine och utvecklaren kör bara gratisvarianten vilket bara tillåter ett visst antal requester per dygn. När det inträffar så kommer blockeringsfunktionen att sluta fungera tills tjänsten får ny quota.
Min lösning på det är att tillhandahålla min egen tjänst skriven i PHP. Den är inte publik och om jag släpper URL:en dit så riskerar den att bli överbelastad. Det är enkelt att skapa det själv med följande PHP-kod:
http://pastie.org/3301306 (Klicka på länken och hämta koden från Pastie)
PHP-skriptet skickar först ut headers som anger att det är en response i JSON och att inget ska cachas. Sedan plockar det ut IP-adress, hostname och eventuell callback-parameter och skriver ut det i JSON-format. Om en callback-parameter är angiven så läggs JSON-svaret som ett argument till angiven funktion. Det gör att när man bäddar in skriptet i en webbsida så kommer den automatiskt anropa callback-funktionen.
2012-01-23
Portable Apps
Portable Apps
Keep your favorite apps with you at all times and run them from any computer without the need to install them.
Setup TrueCrypt volume
- Download and install Truecrypt: http://www.truecrypt.org/
- Choose Extract mode
- Select the USB drive as location.
- Start TrueCrypt.exe
- Press Create Volume and choose (use default values when you don't know what to choose):
- Create an encrypted file container
- Standard TrueCrypt volume
- Press Select File... and browse to the USB Drive and choose a name for the volume, for example: truecrypt_volume
- Set Volume Size to wanted size. Save some space for non encrypted files. Also consider the time it will take to move the volume between disks when you do backups
- Choose Yes for Large file storage
- Format the volume
- Create Traveler Disk Setup
- Choose Tools->Traveler Disk Setup
- Create traveler disk files in the root of the USB Drive
- Do not include TrueCrypt Volume Creation Wizard unless you need to create new volumes on the go
- In Autorun Configuration upon insertion of traveler disk "Auto-mount TrueCrype volume"
- In Mount Settings choose a suitable drive letter
- Mount the volume and continue with the setup for Portable Apps
Setup Portable Apps
- Download Portable Apps: http://portableapps.com/download
- Install Portable Apps on the mounted volume
- Start Portable Apps from the mounted volume (it should autostart)
- Press Manage Apps and choose the apps to install
Recommended appsDevelopment: Database Browser, Notepad++Graphics and pictures: GIMP, Inkscape, BlenderInternet: Chrome, Firefox, Filezilla, Pidgin, Skype, uTorrent, , PuTTY, WinSCPMusic and video: VLCSecurity: KeePassUtilities: 7-Zip, TeamViewer, WinMerge
Mount encrypted volume in computer to prevent latency
A USB Drive often has a lower data rate than the hard drive so you might experience some latency running apps from the USB Drive. A way to prevent latency but still get the benefits of Portable Apps is to move the encrypted volume with Portable Apps to the computer and mount it directly from a folder.
Benefits
- Decrease latency
- Backup of your encrypted volume
Drawbacks
- When you update Portable Apps with new apps or change settings in your current apps you need to move back the changed volume and update all local copies. It is just an easy copy-paste operation, but easy to forget.
2012-01-12
HTML5, apputveckling och programmering
Jag började skriva ett inlägg på Swedroid om HTML5 och apputveckling, men det svävade iväg och blev mer allmänna funderingar och åsikter kring programmering och systemutveckling, så det passade bättre här.
HTML5 ska man absolut satsa på och är ett naturligt steg när det gäller webbutveckling och kanske enklare apputveckling. När väl stödet från webbläsarna blir tillräckligt stort så kommer det bli riktigt användbart för att slippa skapa så många klienter. Det ständiga sorgebarnet Internet Explorer håller tillbaks takten. Inte ens IE9 har tillräckligt stort stöd för HTML5. Vad kommer i version 10? Förhoppningsvis gör de en stor satsning på HTML5 och kommer ikapp sina konkurrenter på det området i alla fall.
Jämförelse mellan olika webbläsares stöd av HTML5.
Det kommer dock aldrig ta bort behovet av att man kan programmera på "riktigt" också. Sen om koden hamnar i appen eller på servern är en annan fråga. En app består sällan bara av klienten på telefonen. Det tillkommer oftast webbklient i HTML, Javascript + js-ramverk (jQuery, Dojo...) och CSS tillsammans med alla tänkbara tekniker och ramverk både på klient och server (JSP, PHP, Velocity...). Sen kommer själva servern (ofta Java på JBoss, Tomcat... eller varför inte Python på App Engine) och databasen (oftast någon typ av relationsdatabas, men populärt är även olika typer av NoSQL-databaser).
Det är sällan företag bara vill ha en app och inget mer. Försök att kunna leverera hela kedjan så att man förstår alla delar av applikationen och inte begränsar sig till bara appen på klienten. Det betyder inte att man alltid ska leverera hela kedjan, men förståelsen skapar bättre produkter.
Grundläggande tekniker för mig när jag arbetar, som jag använder så gott som varje dag och som jag tycker är bra att behärska något så när i alla fall eftersom man stöter på dem hela tiden:
-HTML4 och 5, Javascript + jQuery, CSS, JSON
-Java (SE + EE), webservices (soap och rest), servlets
-SQL och design av relationsdatabaser
Kul och användbara tekniker jag tycker man bör kolla upp så man har vet på vad det handlar om:
-Git och SVN (subversion) - det finns säkert många företag som kör Clearcase, Mercurial och annat men med Git och SVN så får man koll på hur de flesta versionshanteringssystem fungerar
-Enhetstestning och mockramverk - jUnit + Mockito underlättar massor när man gör enhetstester
-Continuous build and integration - Jenkins
-NoSQL
-App Engine
2012-01-11
Uppgradera Nexus S till ICS (Android 4.0.3)
Nu tröttnade jag på att vänta på en OTA-uppdatering och gjorde ett försök att lägga på ICS, dvs. Android 4.0.3. Värt att nämna är att jag köpte min Nexus S i USA, men jag tror inte att något är annorlunda med den svenska varianten.
- Gör en backup av sånt du vill ha kvar + en kopia på hela SD-kortet/USB Storage
- Om du har 2-stegsverifiering kan det vara smart att stänga av det. Jag fick använda en av mina utskriva backupkoder för att komma in i telefonen efter uppgraderingen.
- Gör sedan en factory reset. Annars kommer mycket att strula vid uppstart av ICS. Jag gjorde en total factory reset med tömning av USB Storage efter att jag uppgraderat, men bättre att göra det innan så slipper ni allt strul.
- Ladda hem OTA-paketet från Google: länk (Det är version 4.0.3, 128 MB)
- Döp om filen till update.zip för enkelhetens skull
- Koppla telefonen till din dator och slå på USB storage
- Flytta update.zip till telefonen
- Slå av USB storage och stäng av telefonen helt (power off)
- Håll in Volym upp-knappen och slå på den igen
- Använd volym-knapparna och markera "recovery", gör valet med Power-knappen, nu startar telefonen om igen
- När varningstriangeln och Androiden dyker upp så håller du in Power-knappen och trycker Volym upp
- I menyn som dyker upp väljer du "apply update from /sdcard" med volym-knapparna och trycker på Power-knappen
- Välj update.zip från listan med filer och tryck återigen på Power-knappen
- Vänta och hoppas på det bästa....
- Klart! Det tog 3 minuter.
- Välj "reboot system now" och tryck på Power-knappen.
- Vänta på att rebooten ska bli klar...ny häftig boot-animation...flera upgrade-steg...som nog tog uppåt 10 minuter
- Klart!
De flesta av mina gamla appar återinstallerades. Så jag fick börja med att göra en storstädning av vad jag hade installerat. Funktionaliteten i en del gamla appar är numera inbyggd i operativsystemet så de behövs inte längre. Sen ville jag få en fräsch start så jag avinstallerade allt som jag inte använt på ett par veckor.
Första intrycket av Ice Cream Sandwich är att det känns väldigt fräscht och fungerar bra. Det kommer nog att ta några dagar innan jag vant mig vid de funktioner som flyttats runt, men allt känns välgjort och genomtänkt.
Browser to Android phone
Open links on your Android device from the browser. If any text is selected in the browser it will be copied to the Android clipboard.
- Install the browser extension/addon
- Install "Chrome to Phone" on your Android device
- Start the app on your phone to set it up
- Click the icon in your browser to set it up
- Done! It is ready to be used.
Notes:
- Android 2.2 (Froyo) or later required
2012-01-03
Prenumerera på:
Inlägg (Atom)