Kamera deneyiminizi ortaya çıkarın

1. Başlamadan önce

Katlanabilir telefonları özel kılan nedir?

Katlanabilir cihazlar, nesilde bir kez görülebilecek yeniliklerdir. Benzersiz deneyimler sunan katlanabilir cihazlar, kullanıcılarınızı eller serbest kullanım için masaüstü kullanıcı arayüzü gibi farklı özelliklerle memnun etme konusunda benzersiz fırsatlar sunar.

Ön koşullar

  • Android uygulamaları geliştirme hakkında temel düzeyde bilgi
  • Hilt bağımlılık ekleme çerçevesi hakkında temel bilgiler

Ne oluşturacaksınız?

Bu codelab'de, katlanabilir cihazlar için optimize edilmiş düzenlere sahip bir kamera uygulaması oluşturacaksınız.

6caebc2739522a1b.png

Herhangi bir cihaz duruşuna tepki vermeyen veya gelişmiş selfie'ler için daha iyi olan arka kameradan yararlanmayan temel bir kamera uygulamasıyla başlarsınız. Cihaz açıldığında önizlemeyi daha küçük ekrana taşımak ve telefonu masaüstü moduna ayarlamaya tepki vermek için kaynak kodu güncellersiniz.

Bu API için en uygun kullanım alanı kamera uygulaması olsa da bu codelab'de öğrendiğiniz özelliklerin her ikisi de herhangi bir uygulamaya uygulanabilir.

Neler öğreneceksiniz?

  • Duruş değişikliğine tepki vermek için Jetpack Window Manager'ı kullanma
  • Uygulamanızı katlanabilir cihazların küçük ekranına taşıma

Gerekenler

  • Android Studio'nun son sürümü
  • Katlanabilir cihaz veya katlanabilir emülatör

2. Hazırlanın

Başlangıç kodunu alma

  1. Git yüklüyse aşağıdaki komutu çalıştırmanız yeterlidir. Git'in yüklü olup olmadığını kontrol etmek için terminale veya komut satırına git --version yazın ve doğru şekilde yürütüldüğünü doğrulayın.
git clone https://github.com/android/large-screen-codelabs.git
  1. İsteğe bağlı: Git'iniz yoksa bu codelab'in tüm kodunu indirmek için aşağıdaki düğmeyi tıklayabilirsiniz:

İlk modülü açın

  • Android Studio'da /step1 bölümündeki ilk modülü açın.

Bu codelab ile ilgili kodu gösteren Android Studio'nun ekran görüntüsü

En yeni Gradle sürümünü kullanmanız istenirse güncelleyin.

3. Çalıştırın ve gözlemleyin

  1. Kodu step1 modülünde çalıştırın.

Gördüğünüz gibi bu basit bir kamera uygulamasıdır. Ön ve arka kamera arasında geçiş yapabilir ve en-boy oranını ayarlayabilirsiniz. Ancak soldan ilk düğme şu anda hiçbir işe yaramıyor. Bu düğme, Arka Selfie modunun giriş noktası olacak.

a34aca632d75aa09.png

  1. Şimdi cihazı, menteşenin tamamen düz veya kapalı olmadığı ancak 90 derecelik bir açı oluşturduğu yarı açık konuma getirmeyi deneyin.

Gördüğünüz gibi, uygulama farklı cihaz duruşlarına yanıt vermediğinden düzen değişmiyor ve menteşe vizörün ortasında kalıyor.

4. Jetpack WindowManager hakkında bilgi

Jetpack WindowManager kitaplığı, uygulama geliştiricilerin katlanabilir cihazlar için optimize edilmiş deneyimler oluşturmasına yardımcı olur. Esnek bir ekrandaki katlamayı veya iki fiziksel ekran paneli arasındaki menteşeyi açıklayan FoldingFeature sınıfını içerir. API'si, cihazla ilgili önemli bilgilere erişim sağlar:

FoldingFeature sınıfı, occlusionType() veya isSeparating() gibi ek bilgiler içerir ancak bu codelab'de bunlar ayrıntılı olarak ele alınmaz.

Kitaplık, 1.2.0-beta01 sürümünden itibaren WindowAreaController API'sini kullanır. Bu API, arka ekran modunun geçerli pencereyi arka kamerayla hizalı ekrana taşımasına olanak tanır. Bu özellik, arka kamerayla selfie çekmek ve diğer birçok kullanım alanı için idealdir.

Bağımlılık ekleme

  • Uygulamanızda Jetpack WindowManager'ı kullanmak için aşağıdaki bağımlılıkları modül düzeyindeki build.gradle dosyanıza eklemeniz gerekir:

step1/build.gradle

def work_version = '1.2.0-beta01'
implementation "androidx.window:window:$work_version"
implementation "androidx.window:window-java:$work_version"
implementation "androidx.window:window-core:$work_version"

Artık uygulamanızda hem FoldingFeature hem de WindowAreaController sınıflarına erişebilirsiniz. Bu sınıfları, katlanabilir cihazlarda en iyi kamera deneyimini sunmak için kullanabilirsiniz.

5. Arka Selfie modunu uygulama

Arka Ekran moduyla başlayın.

Bu moda olanak tanıyan API, WindowAreaController API'sidir. Bu API, pencerelerin bir cihazdaki ekranlar veya ekran alanları arasında taşınmasıyla ilgili bilgileri ve davranışları sağlar.

Bu işlev, şu anda etkileşim kurulabilen WindowAreaInfo listesini sorgulamanıza olanak tanır.

WindowAreaInfo kullanarak WindowAreaSession'ye (etkin pencere alanı özelliğini ve belirli bir WindowAreaCapability. için kullanılabilirlik durumunu temsil eden bir arayüz) erişebilirsiniz.

  1. Bu değişkenleri MainActivity içinde tanımlayın:

step1/MainActivity.kt

private lateinit var windowAreaController: WindowAreaController
private lateinit var displayExecutor: Executor
private var rearDisplaySession: WindowAreaSession? = null
private var rearDisplayWindowAreaInfo: WindowAreaInfo? = null
private var rearDisplayStatus: WindowAreaCapability.Status =
    WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED
private val rearDisplayOperation = WindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREA
  1. Ve bunları onCreate() yönteminde başlatın:

step1/MainActivity.kt

displayExecutor = ContextCompat.getMainExecutor(this)
windowAreaController = WindowAreaController.getOrCreate()

lifecycleScope.launch(Dispatchers.Main) {
  lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
    windowAreaController.windowAreaInfos
      .map{info->info.firstOrNull{it.type==WindowAreaInfo.Type.TYPE_REAR_FACING}}
      .onEach { info -> rearDisplayWindowAreaInfo = info }
      .map{it?.getCapability(rearDisplayOperation)?.status?:  WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED }
      .distinctUntilChanged()
      .collect {
           rearDisplayStatus = it
           updateUI()
      }
  }
}
  1. Şimdi, arka özçekim düğmesini etkinleştirmek veya devre dışı bırakmak için mevcut duruma bağlı olarak updateUI() işlevini uygulayın:

step1/MainActivity.kt

private fun updateUI() {
    if(rearDisplaySession != null) {
        binding.rearDisplay.isEnabled = true
        // A session is already active, clicking on the button will disable it
    } else {
        when(rearDisplayStatus) {
            WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED -> {
                binding.rearDisplay.isEnabled = false
                // RearDisplay Mode is not supported on this device"
            }
            WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNAVAILABLE -> {
                binding.rearDisplay.isEnabled = false
                // RearDisplay Mode is not currently available
            }
            WindowAreaCapability.Status.WINDOW_AREA_STATUS_AVAILABLE -> {
                binding.rearDisplay.isEnabled = true
                // You can enable RearDisplay Mode
            }
            WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE -> {
                binding.rearDisplay.isEnabled = true
                // You can disable RearDisplay Mode
            }
            else -> {
                binding.rearDisplay.isEnabled = false
                // RearDisplay status is unknown
            }
        }
    }
}

Bu son adım isteğe bağlıdır ancak WindowAreaCapability.

  1. Şimdi, özellik zaten etkinse oturumu kapatacak veya transferActivityToWindowArea işlevini çağıracak olan toggleRearDisplayMode işlevini uygulayın:

step1/CameraViewModel.kt

private fun toggleRearDisplayMode() {
    if(rearDisplayStatus == WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE) {
        if(rearDisplaySession == null) {
            rearDisplaySession = rearDisplayWindowAreaInfo?.getActiveSession(rearDisplayOperation)
        }
        rearDisplaySession?.close()
    } else {
        rearDisplayWindowAreaInfo?.token?.let { token ->
            windowAreaController.transferActivityToWindowArea(
                token = token,
                activity = this,
                executor = displayExecutor,
                windowAreaSessionCallback = this
            )
        }
    }
}

MainActivity ifadesinin WindowAreaSessionCallback olarak kullanıldığına dikkat edin.

Arka Ekran API'si, dinleyici yaklaşımıyla çalışır: İçeriği diğer ekrana taşımayı istediğinizde, dinleyicinin onSessionStarted() yöntemiyle döndürülen bir oturum başlatırsınız. Bunun yerine içteki (ve daha büyük) ekrana dönmek istediğinizde oturumu kapatırsınız ve onSessionEnded() yönteminde onay alırsınız. Böyle bir dinleyici oluşturmak için WindowAreaSessionCallback arayüzünü uygulamanız gerekir.

  1. MainActivity beyanını, WindowAreaSessionCallback arayüzünü uygulayacak şekilde değiştirin:

step1/MainActivity.kt

class MainActivity : AppCompatActivity(), WindowAreaSessionCallback

Şimdi onSessionStarted ve onSessionEnded yöntemlerini MainActivity içinde uygulayın. Bu geri çağırma yöntemleri, oturum durumu hakkında bildirim almak ve uygulamayı buna göre güncellemek için son derece yararlıdır.

Ancak bu kez, basitlik adına yalnızca işlev gövdesinde hata olup olmadığını kontrol edin ve durumu günlüğe kaydedin.

step1/MainActivity.kt

override fun onSessionEnded(t: Throwable?) {
    if(t != null) {
        Log.d("Something was broken: ${t.message}")
    }else{
        Log.d("rear session ended")
    }
}

override fun onSessionStarted(session: WindowAreaSession) {
    Log.d("rear session started [session=$session]")
}
  1. Uygulamayı oluşturup çalıştırın. Ardından cihazınızı açıp arka ekran düğmesine dokunduğunuzda aşağıdaki gibi bir mesajla karşılaşırsınız:

3fa50cce0b0d4b8d.png

  1. İçeriğinizin dış ekrana taşındığını görmek için "Ekranları şimdi değiştir"i seçin.

6. Masaüstü modunu uygulama

Şimdi uygulamanızı katlanmaya duyarlı hale getirmenin zamanı geldi: Katlanma yönüne göre içeriğinizi cihazın menteşesinin yanına veya üstüne taşıyın. Bunu yapmak için FoldingStateActor içinde hareket edeceksiniz. Böylece kodunuz, daha kolay okunabilmesi için Activity'den ayrılacak.

Bu API'nin temel bölümü, WindowInfoTracker arayüzünden oluşur. Bu arayüz, Activity gerektiren statik bir yöntemle oluşturulur:

step1/CameraCodelabDependencies.kt

@Provides
fun provideWindowInfoTracker(activity: Activity) =
        WindowInfoTracker.getOrCreate(activity)

Bu kod zaten mevcut olduğundan yazmanıza gerek yoktur ancak WindowInfoTracker öğesinin nasıl oluşturulduğunu anlamak için faydalıdır.

  1. Pencere değişikliklerini dinlemek için onResume() yöntemindeki bu değişiklikleri dinleyin:Activity

step1/MainActivity.kt

lifecycleScope.launch {
    foldingStateActor.checkFoldingState(
         this@MainActivity, 
         binding.viewFinder
    )
}
  1. Şimdi FoldingStateActor dosyasını açın. checkFoldingState() yöntemini doldurmanın zamanı geldi.

Daha önce gördüğünüz gibi, Activity'nizin RESUMED aşamasında çalışır ve düzen değişikliklerini dinlemek için WindowInfoTracker'den yararlanır.

step1/FoldingStateActor.kt

windowInfoTracker.windowLayoutInfo(activity)
      .collect { newLayoutInfo ->
         activeWindowLayoutInfo = newLayoutInfo
         updateLayoutByFoldingState(cameraViewfinder)
      }

WindowInfoTracker arayüzünü kullanarak windowLayoutInfo() işlevini çağırabilir ve DisplayFeature içinde bulunan tüm bilgileri içeren bir WindowLayoutInfo Flow toplayabilirsiniz.

Son adım, bu değişikliklere tepki vermek ve içeriği buna göre taşımaktır. Bu işlemi updateLayoutByFoldingState() yöntemi içinde, her seferinde bir adım olacak şekilde yaparsınız.

  1. activityLayoutInfo öğesinin bazı DisplayFeature özellikleri içerdiğinden ve bunlardan en az birinin FoldingFeature olduğundan emin olun. Aksi takdirde herhangi bir işlem yapmanız gerekmez:

step1/FoldingStateActor.kt

val foldingFeature = activeWindowLayoutInfo?.displayFeatures
            ?.firstOrNull { it is FoldingFeature } as FoldingFeature?
            ?: return
  1. Cihaz konumunun düzeninizi etkilediğinden ve hiyerarşinizin sınırları dışında olmadığından emin olmak için katlama yerinin konumunu hesaplayın:

step1/FoldingStateActor.kt

val foldPosition = FoldableUtils.getFeaturePositionInViewRect(
            foldingFeature,
            cameraViewfinder.parent as View
        ) ?: return

Artık düzeninizi etkileyen bir FoldingFeature olduğunuza göre içeriğinizi taşımanız gerekiyor.

  1. FoldingFeature simgesinin HALF_OPEN olup olmadığını kontrol edin. Aksi takdirde içeriğinizin konumunu geri yüklemeniz yeterlidir. HALF_OPEN ise başka bir kontrol yapmanız ve katlama yönüne göre farklı şekilde hareket etmeniz gerekir:

step1/FoldingStateActor.kt

if (foldingFeature.state == FoldingFeature.State.HALF_OPENED) {
    when (foldingFeature.orientation) {
        FoldingFeature.Orientation.VERTICAL -> {
            cameraViewfinder.moveToRightOf(foldPosition)
        }
        FoldingFeature.Orientation.HORIZONTAL -> {
            cameraViewfinder.moveToTopOf(foldPosition)
        }
    }
} else {
    cameraViewfinder.restore()
}

Ekranın katlanma noktası VERTICAL ise içeriğinizi sağa taşırsınız, aksi takdirde katlanma noktasının üzerine taşırsınız.

  1. Uygulamanızı oluşturup çalıştırın, ardından cihazınızı açıp masaüstü moduna getirin. İçeriğin buna göre hareket ettiğini göreceksiniz.

7. Tebrikler!

Bu codelab'de, arka ekran modu veya masaüstü modu gibi katlanabilir cihazlara özgü bazı özellikler ve bunları Jetpack WindowManager kullanarak nasıl etkinleştireceğiniz hakkında bilgi edindiniz.

Kamera uygulamanızda mükemmel kullanıcı deneyimleri sunmaya hazırsınız.

Daha fazla bilgi

Reference