Uwaga: ta strona dotyczy pakietu Aparat2. Jeśli Twoja aplikacja nie wymaga konkretnych funkcji niskiego poziomu z Camera2, zalecamy użycie CameraX. Zarówno CameraX, jak i Camera2 obsługują Androida 5.0 (poziom interfejsu API 21) i nowsze.
Podglądy aparatów i aparatów nie zawsze mają tę samą orientację na Androidzie urządzenia.
Aparat ma ustaloną pozycję na urządzeniu, niezależnie od tego, czy jest to telefon, tablet czy komputer. Gdy zmienia się orientacja urządzenia, zmienia się też orientacja kamery.
W związku z tym aplikacje aparatu zwykle przyjmują stałą relację między od orientacji urządzenia i formatu obrazu podglądu z aparatu. Gdy telefonu jest w orientacji pionowej, podgląd aparatu zakłada, że jest wyższy. niż ma szerokość. Gdy telefon (i kamera) jest obrócony w poziomie, podgląd aparatu powinien być szerszy niż wyższy.
Te założenia podważają jednak nowe formaty, takie jak urządzenia składane , i trybów wyświetlania, takich jak wiele okien oraz Wiele ekranów. Urządzenia składane zmieniają rozmiar wyświetlacza i format obrazu bez zmian orientacji ekranu. Tryb wielu okien ogranicza aplikacje aparatu do części na ekranie, skalując podgląd z aparatu niezależnie od orientacji urządzenia. Tryb wielu ekranów umożliwia korzystanie z dodatkowych ekranów, które mogą mieć inną orientację niż ekran główny.
Orientacja aparatu
Definicja zgodności z Androidem określa, że czujnik obrazu aparatu „MUSI być ustawiony tak, aby dłuższy wymiar aparatu był zgodny z dłuższym wymiarem ekranu. Oznacza to, że gdy urządzenie jest ustawione poziomo, aparat MUSI robić zdjęcia do orientacji poziomej. Dotyczy to niezależnie od naturalnej orientacji urządzenia, czyli zarówno urządzeń z główną orientacją poziomą, jak i z główną orientacją pionową”.
Układ kamery i ekranu maksymalizuje obszar wyświetlania kamery wizjer w aplikacji aparatu. Ponadto czujniki obrazu zwykle zapisują dane w format obrazu w orientacji poziomej, gdzie najczęściej jest używany format 4:3.

Czujnik aparatu ma naturalną orientację poziomą. Na ilustracji 1 czujnik przedniego aparatu (skieruj aparat w tym samym kierunku co wyświetlacza) jest obracany o 270 stopni względem telefonu, aby zapewnić Definicja zgodności z Androidem.
Aby udostępnić aplikacjom obrót czujnika,
Interfejs API camera2 obejmuje
SENSOR_ORIENTATION
jest stała. W przypadku większości telefonów i tabletów urządzenie zgłasza orientację czujnika.
270 stopni dla przedniego aparatu i 90 stopni
dla tylnej części urządzenia, aby zapewnić jej dłuższą krawędź.
przylegaj do czujnika dłuższą krawędzią urządzenia. Kamery w laptopach zwykle raportują orientację czujnika 0 lub 180 stopni.
Czujniki obrazu z aparatu zapisują dane (bufor obrazu) w
w naturalnej orientacji czujnika (poziomo), bufor obrazu należy obracać
liczba stopni określonej przez SENSOR_ORIENTATION
na podgląd z aparatu
wyświetlają się pionowo w naturalnej orientacji. W przypadku aparatów przednich
obraca się w lewo. dla aparatów z tyłu, w prawo.
Na przykład w przypadku przedniego aparatu na rysunku 1 bufor obrazu wygenerowany przez czujnik aparatu wygląda tak:

Obraz musi być obrócony o 270 stopni w przeciwnym kierunku do ruchu wskazówek zegara, aby orientacja podglądu odpowiadała orientacji urządzenia:

Z aparatu tylnego pochodzi bufor obrazu o tej samej orientacji jak bufor powyżej, ale SENSOR_ORIENTATION
to 90 stopni. W rezultacie
jest obrócony o 90 stopni w prawo.
Obracanie urządzenia
Obrót urządzenia to liczba stopni obrócenia urządzenia orientacji ekranu. Na przykład telefon w orientacji poziomej o 90 lub 270 stopni, w zależności od kierunku obrotu.
Bufor obrazu z czujnika aparatu musi być obrócony o taką samą liczbę stopni jak obrotu urządzenia (oprócz stopni pochylenia czujnika) w by podgląd z aparatu był ustawiony pionowo.
Obliczanie orientacji
Prawidłowa orientacja podglądu z aparatu uwzględnia czujnika. orientację i obrót urządzenia.
Ogólny obrót bufora obrazu czujnika można obliczyć za pomocą funkcji następujący wzór:
rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360
gdzie sign
to 1
dla aparatów przednich, a -1
dla aparatów tylnych.
W przypadku przednich aparatów bufor obrazu jest obracany w przeciwnym kierunku niż wskazówki zegara (w stosunku do naturalnej orientacji czujnika). W przypadku aparatów tylnych bufor obrazu jest obrócony w prawo.
Wyrażenie deviceOrientationDegrees * sign + 360
zmienia obrót urządzenia z przeciwnego do wskazówek zegara na zgodny z wskazówkami zegara w przypadku tylnych kamer (np. z 270 stopni w przeciwnym do wskazówek zegara na 90 stopni w zgodnym z wskazówkami zegara). Operacja modulo powoduje, że wynik jest mniejszy niż 360 stopni (np. skalowanie 540 stopni obrotu do 180).
Różne interfejsy API raportują rotację urządzeń w różny sposób:
Display#getRotation()
pozwala na obrót urządzenia w przeciwnym kierunku niż wskazówki zegara (z perspektywy użytkownika). Ta wartość zostaje dodana do powyższej formuły w niezmienionej formie.OrientationEventListener#onOrientationChanged()
zwraca obrót urządzenia zgodnie z kierunkiem ruchu wskazówek zegara (z perspektywy użytkownika). Odwrotna wartość do użycia w formule powyżej.
Przednie aparaty

Oto bufor obrazu utworzony przez czujnik aparatu na rysunku 2:

Aby dostosować bufor do orientacji czujnika, należy obrócić go o 270° w przeciwnym kierunku do ruchu wskazówek zegara (patrz Orientacja kamery powyżej):

Następnie bufor jest obrócony o dodatkowe 90 stopni w lewo, biorąc pod uwagę obrót urządzenia, co spowoduje uzyskanie prawidłowej orientacji podgląd aparatu na ilustracji 2:

Oto kamera obrócona w prawo, aby uzyskać orientację poziomą:

Oto bufor obrazu:

Aby dostosować go do orientacji czujnika, bufor musi zostać obrócony o 270 stopni w przeciwnym kierunku do ruchu wskazówek zegara:

Następnie bufor jest obrócony o kolejne 270 stopni w lewo, aby uwzględnić obrót urządzenia:

Tylne aparaty
Tylne aparaty mają zazwyczaj orientację 90 stopni widoczne z tyłu urządzenia). Podczas ustawiania podglądu z aparatu funkcja bufor obrazu czujnika jest obrócony w prawo zgodnie z intensywnością obrotu czujnika (a nie w lewo, jak w przypadku przednich aparatów), a następnie obraz bufor jest obrócony w lewo zgodnie z obrotem urządzenia.

Na ilustracji 4 widać bufor obrazu z czujnika aparatu:

Aby dostosować orientację czujnika, bufor musi zostać obrócony o 90 stopni w prawo:

Następnie bufor obraca się o 270 stopni w lewo, by uwzględnić rotacja:

Format obrazu
Format obrazu zmienia się, gdy zmienia się orientacja urządzenia, ale także wtedy, gdy składane urządzenia są składane i rozkładane, gdy zmienia się rozmiar okien w otoczeniu z wieloma oknami oraz gdy aplikacje otwierają się na ekranach dodatkowych.
Bufor obrazu z czujnika aparatu musi być zorientowany i przeskalowany tak, aby orientacja i współczynnik proporcji elementu interfejsu wizjera. dynamicznie zmienia orientację – niezależnie od tego, czy zmienia się urządzenie orientacji ekranu.
W przypadku nowych formatów, trybów wielu okien lub wyświetlaczy, jeśli aplikacja przyjmuje, że podgląd z aparatu ma taką samą orientację jak urządzenie (pionowej lub poziomej) podgląd może mieć nieprawidłową orientację lub przeskalowanie nieprawidłowo lub jedno i drugie.

Na rysunku 5 aplikacja błędnie założyła, że urządzenie zostało obrócone o 90 stopni w przeciwnym kierunku ruchu wskazówek zegara, więc obróciła podgląd o ten sam kąt.

Na ilustracji 6 aplikacja nie dostosowała formatu obrazu bufora do włącz jego odpowiednie skalowanie, aby pasowało do nowych wymiarów interfejsu podglądu aparatu. .
W aplikacjach o stałej orientacji ekranu zazwyczaj występują problemy na urządzeniach składanych i na innych urządzeniach z dużym ekranem, takich jak laptopy:

Na rysunku 7 interfejs aplikacji aparatu jest wyświetlany w poziomie, ponieważ orientacja aplikacji jest ograniczona tylko do orientacji poziomej. Obraz w wizjerze jest poprawnie ustawiony. względem czujnika aparatu.
Tryb wstawki w orientacji pionowej
Aplikacje aparatu, które nie obsługują trybu wielookiennego (resizeableActivity="false"
) i ograniczają orientację (screenOrientation="portrait"
lub screenOrientation="landscape"
), można umieścić w trybie wstawki w orientacji pionowej na urządzeniach z dużym ekranem, aby prawidłowo ustawić podgląd aparatu.
W trybie pionowym wyświetlaj aplikacje tylko w orientacji pionowej w ramce (w przycisku) nawet wtedy, gdy współczynnik proporcji wyświetlacza jest w orientacji poziomej. W przypadku aplikacji tylko w orientacji poziomej są wyświetlane czarne pasy, mimo że format obrazu jest pionowy. Obraz z kamery jest obracany, aby dopasować go do interfejsu aplikacji, przycięty, aby dopasować go do współczynnika proporcji podglądu z kamery, a następnie przeskalowany, aby wypełnić podgląd.
Tryb wstawki w orientacji pionowej jest wyzwalany po wybraniu formatu obrazu z aparatu z czujnikiem i współczynnikiem proporcji głównej aktywności aplikacji nie są zgodne.

Na ilustracji 8 obrócono aplikację aparatu w orientacji pionowej, aby wyświetlić interfejs. pionowo na wyświetlaczu laptopa. W aplikacji pojawiają się czarne pasy z powodu różnicy proporcje między aplikacją w orientacji pionowej a ekranem w orientacji poziomej. Obraz podglądu w aparacie został obrócony, aby zrównoważyć obrót interfejsu aplikacji (z powodu wbudowanego trybu portretowego). Obraz został przycięty i pomniejszony, aby pasował do orientacji pionowej, co zmniejszyło pole widzenia.
Obrót, przycinanie, skalowanie
Tryb wstawki w orientacji pionowej jest wywoływany w przypadku aplikacji aparatu przeznaczonego tylko do wyświetlania w orientacji pionowej na ekranie w orientacji poziomej:

Aplikacja ma poziome pasy w orientacji pionowej:

Obraz z kamery jest obrócony o 90 stopni, aby dostosować aplikacja:

Obraz jest przycinany do formatu podglądu z aparatu, a następnie skalowany wypełnij podgląd (pole widzenia jest ograniczone):

Na składanych urządzeniach orientacja czujnika aparatu może być pionowa, a format wyświetlacza poziomy:

Podgląd z aparatu jest obracany w celu dostosowania się do orientacji czujnika, Zdjęcie jest właściwie zorientowane w wizjerze, ale aplikacja tylko do wyświetlania w orientacji pionowej jest obrócone.
Wbudowany tryb pionowy wymaga tylko dodania czarnych pasów do aplikacji w orientacji pionowej aby zapewnić prawidłową orientację aplikacji i podglądu z aparatu:

Interfejs API
Od Androida 12 (poziom interfejsu API 31) aplikacje mogą też bezpośrednio sterować wbudowaną obrazem w orientacji pionowej.
za pomocą
SCALER_ROTATE_AND_CROP
właściwość CaptureRequest
zajęcia.
Wartością domyślną jest SCALER_ROTATE_AND_CROP_AUTO
, która umożliwia systemowi wywołanie trybu w formacie portretowym.
SCALER_ROTATE_AND_CROP_90
to zachowanie w trybie portretowym z wstawionym obrazem, jak opisano powyżej.
Nie wszystkie urządzenia obsługują wszystkie wartości SCALER_ROTATE_AND_CROP
. Aby uzyskać listę
obsługiwanych wartości, odwołanie
CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES
Aparat X
biblioteka Jetpack CameraX, umożliwia stworzenie wizjera aparatu pasującego do orientacji czujnika to proste zadanie.
Element układu PreviewView
tworzy podgląd z aparatu, automatycznie dostosowując się do orientacji czujnika,
obracania i skalowania urządzenia. PreviewView
zachowuje proporcje obrazu z kamery, stosując typ skalowania FILL_CENTER
, który umieszcza obraz na środku, ale może go przyciąć, aby dopasować do wymiarów PreviewView
. Aby na obrazie z aparatu ustawić czarne pasy, ustaw typ skali na
FIT_CENTER
Podstawowe informacje na temat tworzenia podglądu z kamery w PreviewView
znajdziesz w tych artykułach:
Zaimplementuj podgląd.
Pełną przykładową implementację znajdziesz w
CameraXBasic
w repozytorium GitHub.
CameraViewfinder
Podobnie jak w przypadku korzystania z funkcji Podgląd biblioteka CameraViewfinder udostępnia zestaw narzędzi, które upraszczają tworzenie podglądu z kamery. Nie zależy ona od CameraX Core, więc możesz ją łatwo zintegrować z dotychczasową bazą kodu Camera2.
Zamiast używać bezpośrednio aplikacji
Surface
możesz wyświetlić obraz z kamery Camera2 za pomocą widżetu
CameraViewfinder
.
CameraViewfinder
używa wewnętrznie obiektu TextureView
lub SurfaceView
do wyświetlania obrazu z kamery i zmienia go w wymagany sposób, aby poprawnie wyświetlać wizjer.
Obejmuje to korektę formatu obrazu, skali i obrotu.
Aby poprosić o powierzchnię z obiektu CameraViewfinder
, musisz
utwórz element ViewfinderSurfaceRequest
.
Ta prośba zawiera wymagania dotyczące rozdzielczości powierzchni i informacji o aparacie z CameraCharacteristics
.
Dzwonię pod numer requestSurfaceAsync()
wysyła żądanie do dostawcy powierzchni, którym jest TextureView
lub
SurfaceView
i otrzymuje ListenableFuture
o wartości Surface
.
Dzwonię pod numer markSurfaceSafeToRelease()
powiadamia dostawcę powierzchni, że nie jest ona potrzebna i jest powiązana
zasobów, które można zwolnić.
fun startCamera(){ val previewResolution = Size(width, height) val viewfinderSurfaceRequest = ViewfinderSurfaceRequest(previewResolution, characteristics) val surfaceListenableFuture = cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest) Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> { override fun onSuccess(surface: Surface) { /* create a CaptureSession using this surface as usual */ } override fun onFailure(t: Throwable) { /* something went wrong */} }, ContextCompat.getMainExecutor(context)) }
void startCamera(){ Size previewResolution = new Size(width, height); ViewfinderSurfaceRequest viewfinderSurfaceRequest = new ViewfinderSurfaceRequest(previewResolution, characteristics); ListenableFuture<Surface> surfaceListenableFuture = cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest); Futures.addCallback(surfaceListenableFuture, new FutureCallback<Surface>() { @Override public void onSuccess(Surface result) { /* create a CaptureSession using this surface as usual */ } @Override public void onFailure(Throwable t) { /* something went wrong */} }, ContextCompat.getMainExecutor(context)); }
SurfaceView
SurfaceView
to
do podglądu z aparatu, jeśli podgląd
wymagają przetworzenia i nie jest animowany.
SurfaceView
automatycznie obraca bufor obrazu czujnika aparatu, aby dopasować go do orientacji wyświetlacza, uwzględniając zarówno orientację czujnika, jak i urządzenia. Bufor obrazu jest jednak skalowany tak, aby pasował do: SurfaceView
bez uwzględniania formatu obrazu.
Musisz się upewnić, że format bufora obrazu jest zgodny z formatem
współczynnika SurfaceView
, którą można uzyskać, skalując zawartość
z SurfaceView
w komponencie
onMeasure()
:
(Kod źródłowy computeRelativeRotation()
znajduje się w
Rotacja względna poniżej).
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val width = MeasureSpec.getSize(widthMeasureSpec) val height = MeasureSpec.getSize(heightMeasureSpec) val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees) if (previewWidth > 0f && previewHeight > 0f) { /* Scale factor required to scale the preview to its original size on the x-axis. */ val scaleX = if (relativeRotation % 180 == 0) { width.toFloat() / previewWidth } else { width.toFloat() / previewHeight } /* Scale factor required to scale the preview to its original size on the y-axis. */ val scaleY = if (relativeRotation % 180 == 0) { height.toFloat() / previewHeight } else { height.toFloat() / previewWidth } /* Scale factor required to fit the preview to the SurfaceView size. */ val finalScale = min(scaleX, scaleY) setScaleX(1 / scaleX * finalScale) setScaleY(1 / scaleY * finalScale) } setMeasuredDimension(width, height) }
@Override void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees); if (previewWidth > 0f && previewHeight > 0f) { /* Scale factor required to scale the preview to its original size on the x-axis. */ float scaleX = (relativeRotation % 180 == 0) ? (float) width / previewWidth : (float) width / previewHeight; /* Scale factor required to scale the preview to its original size on the y-axis. */ float scaleY = (relativeRotation % 180 == 0) ? (float) height / previewHeight : (float) height / previewWidth; /* Scale factor required to fit the preview to the SurfaceView size. */ float finalScale = Math.min(scaleX, scaleY); setScaleX(1 / scaleX * finalScale); setScaleY(1 / scaleY * finalScale); } setMeasuredDimension(width, height); }
Więcej informacji o wdrażaniu SurfaceView
jako podglądu aparatu znajdziesz w artykule Ustawienia orientacji kamery.
TextureView
TextureView
jest mniej wydajny niż SurfaceView
(i wymaga więcej pracy), ale TextureView
zapewnia maksymalną kontrolę nad podglądem kamery.
TextureView
obraca bufor obrazu czujnika w zależności od jego orientacji, ale nie obsługuje obracania urządzenia ani skalowania podglądu.
Skalowanie i obrót można zakodować
Transformacja matrycy. Aby dowiedzieć się, jak prawidłowo skalować i obracać TextureView
, zapoznaj się z artykułem Obsługa powierzchni o zmiennym rozmiarze w aplikacji Aparat.
Rotacja względna
Odchylenie względne czujnika aparatu to kąt obrotu wymagany do dopasowania sygnału z czujnika aparatu do orientacji urządzenia.
Obrót względny jest używany przez komponenty takie jak SurfaceView
i TextureView
w celu określenia współczynników skalowania x i y dla obrazu podglądu. Służy ona też do określenia rotacji bufora obrazu czujnika.
Klasy CameraCharacteristics
i Surface
umożliwiają obliczenie względnego obrotu czujnika aparatu:
/** * Computes rotation required to transform the camera sensor output orientation to the * device's current orientation in degrees. * * @param characteristics The CameraCharacteristics to query for the sensor orientation. * @param surfaceRotationDegrees The current device orientation as a Surface constant. * @return Relative rotation of the camera sensor output. */ public fun computeRelativeRotation( characteristics: CameraCharacteristics, surfaceRotationDegrees: Int ): Int { val sensorOrientationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)!! // Reverse device orientation for back-facing cameras. val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT ) 1 else -1 // Calculate desired orientation relative to camera orientation to make // the image upright relative to the device orientation. return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360 }
/** * Computes rotation required to transform the camera sensor output orientation to the * device's current orientation in degrees. * * @param characteristics The CameraCharacteristics to query for the sensor orientation. * @param surfaceRotationDegrees The current device orientation as a Surface constant. * @return Relative rotation of the camera sensor output. */ public int computeRelativeRotation( CameraCharacteristics characteristics, int surfaceRotationDegrees ){ Integer sensorOrientationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); // Reverse device orientation for back-facing cameras. int sign = characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT ? 1 : -1; // Calculate desired orientation relative to camera orientation to make // the image upright relative to the device orientation. return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360; }
Dane dotyczące okien
Rozmiar ekranu nie powinien być używany do określania wymiarów wizjera aparatu. Aplikacja aparatu może działać na części ekranu, w trybie wielu okien na urządzeniach mobilnych lub w trybie swobodnym w ChromeOS.
WindowManager#getCurrentWindowMetrics()
(dodane na poziomie interfejsu API 30) zwraca rozmiar okna aplikacji, a nie
do rozmiaru ekranu. Metody biblioteki Jetpack WindowManager
WindowMetricsCalculator#computeCurrentWindowMetrics()
oraz
WindowInfoTracker#currentWindowMetrics()
zapewniają podobną pomoc dzięki zgodności wstecznej z interfejsem API poziomu 14.
Obrót o 180 stopni
Obrót urządzenia o 180 stopni (na przykład z orientacji naturalnej do
naturalnej orientacji do góry nogami) nie powoduje
onConfigurationChanged()
oddzwanianie. W związku z tym podgląd z aparatu może być do góry nogami.
Aby wykryć obrót o 180 stopni, zaimplementuj funkcję DisplayListener
i sprawdź obrót urządzenia za pomocą wywołania funkcji Display#getRotation()
w połączeniu z wywołaniem onDisplayChanged()
.
Wyjątkowe materiały
Przed Androidem 10 tylko najbardziej widoczna aktywność w trybie wielu okien
było w stanie RESUMED
. Było to mylące dla użytkowników, ponieważ
system nie wskaże, która aktywność została wznowiona.
Android 10 (poziom interfejsu API 29) wprowadziło wielozadaniowość, w której wszystkie widoczne działania są w stanie RESUMED
. Widoczne aktywności nadal mogą trafiać do pola PAUSED
jeśli na przykład nad działaniem znajduje się przezroczysta aktywność lub
aktywności nie można zaznaczyć, na przykład w trybie obrazu w obrazie (patrz
Obsługa funkcji obraz w obrazie).
Aplikacja używająca kamery, mikrofonu lub dowolnych bądź innych
zasób singleton na poziomie API 29 lub wyższym musi obsługiwać wielokrotne wznawianie. Jeśli na przykład 3 wznowione aktywności chcą korzystać z kamery, tylko jedna z nich może uzyskać dostęp do tego zasobu. Każde działanie musi implementować
onDisconnected()
wywołanie zwrotne, aby zwracać uwagę na zapobiegawczy dostęp do kamery przez wyższy priorytet
działania.
Więcej informacji znajdziesz w artykule Wznawianie zadań.
Dodatkowe materiały
- Przykładowe treści znajdziesz w aplikacji Camera2: tutaj w GitHubie.
- Więcej informacji o przypadku użycia podglądu kamery X znajdziesz na stronie Aparat X Zaimplementuj podgląd.
- Przykładową implementację podglądu aparatu w ramach CameraX znajdziesz w repozytorium CameraXBasic w GitHub.
- Informacje o podglądzie aparatu w ChromeOS znajdziesz w artykule Ustawienia aparatu.
- Informacje o programowaniu na urządzenia składane znajdziesz na stronie Więcej informacji o urządzeniach składanych