Gerekli izinleri isteyip aldıktan sonra uygulamanız, ses arabirimli gözlük veya görüntü arabirimli gözlükteki donanıma erişebilir. Telefonun donanımı yerine gözlüğün donanımına erişmek için yansıtılan bağlam kullanmanız gerekir.
Kodunuzun nerede yürütüldüğüne bağlı olarak, yansıtılan bağlamı elde etmenin iki temel yolu vardır:
Kodunuz yansıtılan bir etkinlikte çalışıyorsa yansıtılan bağlamı alma
Uygulamanızın kodu yansıtılan etkinliğinizin içinden çalışıyorsa kendi etkinlik bağlamı zaten yansıtılan bağlamdır. Bu senaryoda, söz konusu etkinlikte yapılan çağrılar gözlüğün donanımına erişebilir.
Telefon uygulaması bileşeninde çalışan kod için öngörülen bağlamı alma
Uygulamanızın, yansıtılan etkinliğinizin dışında kalan bir bölümünün (ör. telefon etkinliği veya hizmet) gözlüğün donanımına erişmesi gerekiyorsa açıkça yansıtılan bir bağlam elde etmesi gerekir. Bunun için createProjectedDeviceContext yöntemini kullanın:
@RequiresApi(Build.VERSION_CODES.BAKLAVA) @OptIn(ExperimentalProjectedApi::class, ExperimentalCoroutinesApi::class) private fun monitorProjectedConnectivity(activity: ComponentActivity) { activity.lifecycleScope.launch { // Before creating a projected context, check to see if the projected device is connected. // While this method returns true, the projected context remains valid. ProjectedContext.isProjectedDeviceConnected(activity, coroutineContext) .collectLatest { isConnected -> if (isConnected) { // From a phone Activity or Service, get a context for the audio and display glasses. // Re-initialize on reconnect: Obtain another context instance. val projectedContext = try { ProjectedContext.createProjectedDeviceContext(activity) } catch (e: IllegalStateException) { Log.e(TAG, "Failed to create projected context", e) return@collectLatest } // Use the projectedContext to initialize system services (e.g., CameraManager). Log.i(TAG, "Projected device connected. Initializing hardware...") } else { // The projected context is destroyed when the device disconnects. // Clean up on disconnect: Listen for 'false' and release resources. Log.i(TAG, "Projected device disconnected. Cleaning up hardware resources...") } } } }
Geçerlilik kontrolü
createProjectedDeviceContext çağrısını ProjectedContext.isProjectedDeviceConnected içine alın. Bu yöntem true döndürürken yansıtılan bağlam, bağlı cihaz için geçerli kalır ve telefon uygulaması etkinliğiniz veya hizmetiniz (ör. CameraManager) yapay zeka destekli akıllı gözlük donanımına erişebilir.
Bağlantı kesildiğinde temizle
Yansıtılan bağlam, bağlı cihazın yaşam döngüsüne bağlıdır. Bu nedenle, cihazın bağlantısı kesildiğinde yok edilir. Cihazın bağlantısı kesildiğinde ProjectedContext.isProjectedDeviceConnected, false değerini döndürür. Uygulamanız bu değişikliği dinlemeli ve uygulamanızın bu yansıtılan bağlamı kullanarak oluşturduğu tüm sistem hizmetlerini (ör. CameraManager) veya kaynakları temizlemelidir.
Yeniden bağlanıldığında yeniden başlatma
Gözlük yeniden bağlandığında uygulamanız, createProjectedDeviceContext kullanarak başka bir yansıtılan bağlam örneği alabilir ve ardından yeni yansıtılan bağlamı kullanarak tüm sistem hizmetlerini veya kaynaklarını yeniden başlatabilir.
Gözlüğün mikrofonuyla ses kaydetme
Bluetooth Eller Serbest Profili'ni (HFP) kullanarak gözlükten ses kaydedebilirsiniz. Bu modda gözlük, standart mikrofonlu kulaklık ve Gelişmiş Ses Dağıtım Profili (A2DP) profillerini kullanarak telefona bağlanır ve tipik bir Bluetooth çevre birimi gibi çalışır. Uygulamanız standart Bluetooth kaydı için tasarlanmışsa ek bir geliştirme yapmadan gözlükten ses kaydetmek için bu yöntemi kullanabilirsiniz.
Bluetooth HFP kullanarak ses kaydetme
Bluetooth HFP kullanarak ses kaydetmek için önce gerekli çalışma zamanı izinlerini isteyin, ardından aşağıdaki bölümlerde açıklandığı gibi AudioManager API'yi kullanarak sesi kaydedin.
İzin iste
Tüm standart Bluetooth ses sistemlerinde olduğu gibi RECORD_AUDIO, BLUETOOTH_CONNECT ve diğer ilgili izinler, bağlı cihaz (ör. sesli gözlük veya görüntülü gözlük) tarafından değil, telefon tarafından kontrol edilir.
İzinleri istemek için aşağıdaki adımları uygulayın:
Uygulamanızın manifest dosyasında aşağıdaki izinleri beyan edin:
Standart Android izin akışını kullanarak çalışma zamanında hem
RECORD_AUDIOhem deBLUETOOTH_CONNECTizinlerini isteyin.
Sesi yönlendirmek için AudioManager'ı kullanma
Kullanıcı, uygulamanıza gerekli çalışma zamanı izinlerini verdikten sonra sesi Bluetooth HFP üzerinden yönlendirmek için AudioManager API'yi kullanarak iletişim cihazını TYPE_BLUETOOTH_SCO olarak ayarlayın. Bu, sisteme Bluetooth çevre biriminden ses alması talimatını verir.
val audioManager = context.getSystemService(AudioManager::class.java) ?: return val devices = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS) val hfpDevice = devices.find { it.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO } hfpDevice?.let { device -> val audioRecord = AudioRecord.Builder() .setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION) .setAudioFormat(audioFormat) .setBufferSizeInBytes(bufferSize) .build() // Route recording to the Bluetooth device audioRecord.setPreferredDevice(device) audioManager.setCommunicationDevice(device) audioRecord.startRecording()
Akıllı gözlüğün kamerasıyla fotoğraf çekme
Gözlüğün kamerasıyla görüntü yakalamak için CameraX'in ImageCapture kullanım alanını ayarlayın ve uygulamanız için doğru bağlamı kullanarak gözlüğün kamerasına bağlayın:
private fun startCameraOnGlasses(activity: ComponentActivity) { activity.lifecycleScope.launch { // Before creating a projected context, check to see if the projected device is connected. ProjectedContext.isProjectedDeviceConnected(activity, coroutineContext) .collectLatest { isConnected -> if (isConnected) { // 1. Get the CameraProvider using the projected context. // When using the projected context, DEFAULT_BACK_CAMERA maps to the audio and display glasses' camera. val projectedContext = try { ProjectedContext.createProjectedDeviceContext(activity) } catch (e: IllegalStateException) { Log.e(TAG, "Projected context could not be created", e) return@collectLatest } val cameraProviderFuture = ProcessCameraProvider.getInstance(projectedContext) cameraProviderFuture.addListener({ val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA // 2. Check for the presence of a camera. if (!cameraProvider.hasCamera(cameraSelector)) { Log.w(TAG, "The selected camera is not available.") return@addListener } // 3. Query supported streaming resolutions using Camera2 Interop. val cameraInfo = cameraProvider.getCameraInfo(cameraSelector) val camera2CameraInfo = Camera2CameraInfo.from(cameraInfo) val cameraCharacteristics = camera2CameraInfo.getCameraCharacteristic( CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP ) // 4. Define the resolution strategy. val targetResolution = Size(1920, 1080) val resolutionStrategy = ResolutionStrategy( targetResolution, ResolutionStrategy.FALLBACK_RULE_CLOSEST_LOWER ) val resolutionSelector = ResolutionSelector.Builder() .setResolutionStrategy(resolutionStrategy) .build() // 5. If you have other continuous use cases bound, such as Preview or ImageAnalysis, // you can use Camera2 Interop's CaptureRequestOptions to set the FPS val fpsRange = Range(30, 60) val captureRequestOptions = CaptureRequestOptions.Builder() .setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange) .build() // 6. Initialize the ImageCapture use case with options. val imageCapture = ImageCapture.Builder() // Optional: Configure resolution, format, etc. .setResolutionSelector(resolutionSelector) .build() try { // Unbind use cases before rebinding. cameraProvider.unbindAll() // Bind use cases to camera using the Activity as the LifecycleOwner. cameraProvider.bindToLifecycle( activity, cameraSelector, imageCapture ) } catch (exc: Exception) { Log.e(TAG, "Use case binding failed", exc) } }, ContextCompat.getMainExecutor(activity)) } } } }
Kodla ilgili önemli noktalar
- Yansıtılan cihaz bağlamını kullanarak
ProcessCameraProviderörneği alır. - Yansıtılan bağlamın kapsamında, kamera seçerken gözlüğün birincil, dışa bakan kamerası
DEFAULT_BACK_CAMERAile eşleşir. - Ön bağlama kontrolü, devam etmeden önce seçilen kameranın cihazda mevcut olduğunu doğrulamak için
cameraProvider.hasCamera(cameraSelector)kullanır. - Temel
CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP'yi okumak içinCamera2CameraInfoile Camera2 Interop'u kullanır. Bu, desteklenen çözünürlüklerle ilgili gelişmiş kontroller için yararlı olabilir. ImageCaptureiçin çıkış görüntüsü çözünürlüğünü hassas bir şekilde kontrol etmek amacıyla özel birResolutionSelectoroluşturulur.- Özel bir
ResolutionSelectorile yapılandırılmış birImageCapturekullanım alanı oluşturur. ImageCapturekullanım alanını etkinliğin yaşam döngüsüne bağlar. Bu, etkinliğin durumuna göre kameranın açılıp kapanmasını otomatik olarak yönetir (örneğin, etkinlik duraklatıldığında kamerayı durdurur).- Tek akışlı donanım için yapılandırma: Gözlük kamera ardışık düzeni, aynı anda tek bir etkin akışla sınırlıdır.
ImageCapturetek başına bağlandığında CameraX, varsayılan olarak odaklama ve ölçüm için dahili bir yinelenen akış (MeteringRepeating) ekler. Bu da tek akışlı ardışık düzenin durmasına neden olur.ImageCaptureöğesini önizleme akışı olmadan tek başına bağlamak içinCameraXConfig.BuilderüzerindesetRepeatingStreamForced(false)ayarını yaparak zorunlu tekrarlanan akışı devre dışı bırakın (örneğin,ApplicationsınıfınızdaCameraXConfig.Provideruygulayarak veya başlatmadan önceProcessCameraProvideröğesini yapılandırarak).
Akıllı gözlüğün kamerası ayarlandıktan sonra CameraX'in ImageCapture sınıfıyla görüntü yakalayabilirsiniz. Resim çekmek için takePicture kullanma hakkında bilgi edinmek üzere CameraX belgelerini inceleyin.
Gözlüğün kamerasıyla video çekme
Gözlüğün kamerasıyla resim yerine video çekmek için ImageCapture bileşenlerini ilgili VideoCapture bileşenleriyle değiştirin ve çekim yürütme mantığını değiştirin.
Ana değişiklikler arasında farklı bir kullanım alanı kullanma, farklı bir çıkış dosyası oluşturma ve uygun video kayıt yöntemini kullanarak yakalama işlemini başlatma yer alır.
VideoCapture API'si ve kullanımı hakkında daha fazla bilgi için CameraX'in video yakalama belgelerine bakın.
Aşağıdaki tabloda, uygulamanızın kullanım alanına bağlı olarak önerilen çözünürlük ve kare hızı gösterilmektedir:
| Kullanım alanı | Çözünürlük | Kare hızı |
|---|---|---|
| Video İletişimi | 1280 x 720 | 15 FPS |
| Bilgisayarlı Görü | 640 x 480 | 10 FPS |
| Yapay Zeka Video Akışı | 640 x 480 | 1 FPS |
Yansıtılan bir etkinlikten telefonun donanımına erişme
Yansıtılan etkinlik, ana makine cihazın (telefon) bağlamını almak için createHostDeviceContext(context) kullanarak telefonun donanımına (ör. kamera veya mikrofon) da erişebilir:
@OptIn(ExperimentalProjectedApi::class) private fun getPhoneContext(activity: ComponentActivity): Context? { return try { // From a projected Activity, get a context for the phone. ProjectedContext.createHostDeviceContext(activity) } catch (e: IllegalStateException) { Log.e(TAG, "Failed to create host device context", e) null } }
Karma bir uygulamada (hem mobil hem de gözlük deneyimleri içeren bir uygulama) ana cihaza (telefon) özgü donanıma veya kaynaklara erişirken uygulamanızın doğru donanıma erişebilmesi için doğru bağlamı açıkça seçmeniz gerekir:
- Telefonun bağlamını almak için telefondan
Activitybağlamını veyaActivityProjectedContext.createHostDeviceContextbağlamını kullanın. getApplicationContextkullanmayın. En son başlatılan bileşen yansıtılan bir etkinlikse uygulama bağlamı, gözlüğün bağlamını yanlış döndürebilir.