(Free)glut – reshape.
Po kilku małych zmianach w kodzie multiplatformowego projektu ( iOS, Android, Win) wykorzystującego OpenGL ( oraz - tylko w wersji Win - freeglut ) doszło do dziwnego zdarzenia. Aplikacja przestała (podczas zmiany rozmiaru okna) wywoływać reshape callback zainstalowany funkcją glutReshapeFunc() . Projekt skompilowany z wykorzystaniem glut (a nie freeglut) działa bez problemu. Niestety, bez freeglut się nie obejdzie. Najprostsze rozwiązanie to obejście problemu - "ręczny" odczyt wymiarów okna i wywoływanie funkcji reshape. Co prawda nie jesteśmy w stanie reagować na wszystkie zmiany rozmiaru okna, ale podpięcie wywołań reshape pod główny timer aplikacji ( 30fps ) zdaje egzamin:
int w = glutGet(GLUT_WINDOW_WIDTH); int h = glutGet(GLUT_WINDOW_HEIGHT); reshape ( w, h );
Placement New.
Czym jest Placement New ? Jest to wersja operatora new, która pozwala na utworzenie obiektu we wcześniej zaallokowanym obszarze pamięci. Jeśli mamy własny system allokacji pamięci i nie chcemy przeładowywać operatorów new, delete i delete[] dla każdej z klas - najprościej użyć Placement New. Jedyny minus to konieczność ręcznego wywołania destruktora i pamiętanie o zwolnieniu zaallokowanej wcześniej pamięci ( podobnie jak przy new /delete
). Mały przykład użycia:
cTest * tmp = new ( myCustomAlloc( sizeof (cTest) ) ) cTest; .... tmp->~cTest(); myCustomFree( tmp ); tmp = NULL;
Lion + OpenOffice + Resume = ?
Jak wiadomo, jedną z nowych cech OS X Lion jest "resume". Po restarcie systemu, aplikacja zostaje przywrócona do stanu sprzed zamknięcia. "Wracają" wszystkie zamknięte okna i dane.
Niestety, u mnie wystąpił mały problem z Open Office (który to pakiet jest naprawdę mocno zabugowany) . Po restarcie aplikacji pojawił się (systemowy?) requester z opcjami do wyboru: przywrócenie stanu poprzedniego lub restart. Niestety. OO nie reagowało na wybór żadnej z nich i z uporem maniaka wyświetlało okno ponownie. Co prawda dało się odpalić Writera w tle, ale menu główne nie reagowało na nic.
Najprostsze rozwiązanie - usunięcie odpowiednich plików (z findera lub terminala). Dane te znajdują się w ~Library/Saved Application State w podkatalogach łatwo identyfikowalnych z daną aplikacją. Dla OO wszystko siedzi w org.openoffice.script.savedState. Wystarczy usunąć katalog wraz z zawartością - i po problemie.
Android Market – certyfikaty
Po kilku poprawkach do aplikacji i ponownym szyfrowaniu ( sign + align ) .apk nie chciał się zainstalować na urządzeniu - Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES]. Sam proces "szyfrowania" nie zmienił się od poprzedniej wersji :
Sign:
jarsigner -verbose -digestalg SHA1 -sigalg MD5withRSA -keystore mykeys.keystore -signedjar test-signed.apk tes-unsigned.apk mykeys.keystore
Align:
zipalign -v 4 test-signed.apk test.apk
Upload:
adb install test.apk
I .. Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES].
Po weryfikacji za pomocą:
jarsigner -verify -verbose -certs test-signed.apk
pojawiło się kilka problemów z certyfikatem - każdy z plików zgłaszał [CertPath not validated: null] .
Plus podsumowanie:
Warning: This jar contains entries whose certificate chain is not validated.
Po przeszukaniu sieci i kilku testach okazało się, że android (a w szczególności market i narzędzia do podpisywania .apk) nie lubi się z JDK > 1.7 . Niestety miałem zainstalowany JDK 1.7.0.0 . Po doinstalowaniu 1.6.0.2i skorzystaniu ze starszej wersji jarsignera - wszystko wróciło do normy.
Instalacja .apk na karcie SD.
W nowej wersji aplikacji klient zdecydował się na umożliwienie instalacji na zewnętrznym nośniku - karcie SD. Sam proces jest szczegółowo opisany na stronie google . Z wcześniejszych założeń wynikało, że aplikacja powinna działać na różnych wersja systemu Android - począwszy od 1.6 (czyli Api Level 4). Jak do tej pory ustawinia minimalnej wersji OS-a (czyli android:minSdkVersion w AndroidManifest.xml ) pokrywały się z wersją OS pod która SDK budował kod wynikowy ( target w default.properties ). By umożliwić instalację na zewnętrznym nośniku, trzeba jednak użyc w AndroidManifest.xml tagów wprowadzonych dopiero w Api Level 8 (Android 2.2) - czyli ustawić target na "android-8". Atrybut android:minSdkVersion pozostaje bez zmian. Podczas kompilacji dostajemy co prawda ostrzeżenie o niższej wersji SDK niż zadeklarowany "target" kompilacji, ale - dopóki nie korzystamy w naszym kodzie z żadnych funkcji API wyższego niż Level 4 - możemy je zignorować.
Do AndroidManifest.xml musimy także dodać atrybut android:installLocation oraz ustawic jego wartość na auto lub preferExternal. Wybrałem opcję pierwszą - system sam decyduje gdzie zainstalować aplikację ( wybór zależy m.in . od ilości wolnego miejsca w internal storage), poza tym użytkownik sam może zadecydować czy (i kiedy) przenieść aplikację na kartę SD czy pozostawić ją w pamięci telefonu. Odpowiednia opcja kopiowania dostępna jest w ustawieniach (oczywiście jeśli używamy Androida >= 2.2 ).