Android 11 ve sonraki sürümlerde Hızlı Erişim Cihaz Kontrolleri özelliği Kullanıcının lambalar, telefon numaraları, e-posta gibi harici cihazlar gibi harici cihazları cihazları ve kameraları, tek bir konumdan üç etkileşim içinde varsayılan başlatıcıdır. Kullanacağı başlatıcıyı cihazın OEM'si seçer. Cihaz Google Home ve üçüncü taraf tedarikçi firma uygulamaları gibi bu alanda görüntülenecek cihazlar sağlayın. Bu sayfada, farklı kullanıcılara kontrol uygulamanıza bağlayabilirsiniz.
Bu desteği eklemek için bir ControlsProviderService
oluşturup beyan edin. Şunu oluşturun:
bağlı olarak uygulamanızın desteklediğini kontrol edebilir ve ardından
bu kontroller için yayıncıdan yararlanabilir.
Kullanıcı arayüzü
Cihazlar, Cihaz denetimleri altında şablonlu widget'lar olarak gösterilir. Beş cihaz denetimi widget'ları aşağıdaki şekilde gösterildiği gibi kullanılabilir:
|
|
|
|
|
Dokunma ve widget'ı basılı tuttuğunuzda daha ayrıntılı kontrol için uygulamaya gidebilirsiniz. Şunları yapabilirsiniz: her widget'ın simgesini ve rengini özelleştirebilirsiniz. Ancak en iyi kullanıcı deneyimi için Varsayılan ayar cihazla eşleşiyorsa varsayılan simgeyi ve rengi kullanmalıdır.
Hizmeti oluşturma
Bu bölümde,
ControlsProviderService
.
Bu hizmet, Android sistem kullanıcı arayüzüne uygulamanızın cihaz kontrolleri içerdiğini bildirir
bölümünde gösterilmesi gerekir.
ControlsProviderService
API, aşağıdaki gibi reaktif akışlar hakkında bilgi sahibi olduğunu varsayar:
Reaktif Akışlar GitHub'ında tanımlanmıştır
proje
ve Java 9 Akışı'nda uygulandı
arayüzler.
API aşağıdaki kavramlar temel alınarak oluşturulmuştur:
- Yayıncı: Uygulamanız yayıncıdır.
- Abone: Sistem kullanıcı arayüzü, abonedir ve sayı isteyebilir. kontrol etmek için kullanır.
- Abonelik: Yayıncının güncellemeleri gönderebileceği zaman aralığı gönderebilirsiniz. Yayıncı veya abone bu ekranı kapatabilir penceresini kapatın.
Hizmeti beyan etme
Uygulamanız MyCustomControlService
gibi bir hizmeti
bildirmelidir.
Hizmet, ControlsProviderService
için bir intent filtresi içermelidir. Bu
filtre, uygulamaların sistem arayüzüne kontrol katkısında bulunmalarını sağlar.
Ayrıca, sistem kullanıcı arayüzündeki denetimlerde görüntülenen bir label
öğesine de ihtiyacınız vardır.
Aşağıdaki örnekte bir hizmetin nasıl tanımlanacağı gösterilmektedir:
<service
android:name="MyCustomControlService"
android:label="My Custom Controls"
android:permission="android.permission.BIND_CONTROLS"
android:exported="true"
>
<intent-filter>
<action android:name="android.service.controls.ControlsProviderService" />
</intent-filter>
</service>
Sonra, MyCustomControlService.kt
adında yeni bir Kotlin dosyası oluşturun ve
ControlsProviderService()
süresini uzat:
Kotlin
class MyCustomControlService : ControlsProviderService() { ... }
Java
public class MyCustomJavaControlService extends ControlsProviderService { ... }
Doğru kontrol türünü seçin
API, kontrolleri oluşturmak için oluşturucu yöntemleri sunar. oluşturucu, kontrol etmek istediğiniz cihazı ve kullanıcının nasıl etkileşimde bulunacağını belirleyin gerçekleşebilir. Aşağıdaki adımları uygulayın:
- Kontrolün temsil ettiği cihaz türünü seçin. İlgili içeriği oluşturmak için kullanılan
DeviceTypes
sınıfı bir desteklenen tüm cihazların numaralandırması. Tür, renklerini ve simgelerini görebilirsiniz. - Kullanıcının gördüğü adı, cihazın konumunu belirleyin. Örneğin, mutfak ve kontrolle ilişkili diğer kullanıcı arayüzü metin öğeleri.
- Kullanıcı etkileşimini desteklemek için en iyi şablonu seçin. Kontrollere
ControlTemplate
kaldırıyor. Bu şablon, doğrudan hem de kullanılabilir giriş yöntemlerini (yaniControlAction
. Aşağıdaki tabloda, kullanılabilir şablonlar ve işlemler özetlenmektedir: şunları desteklerler:
Şablon | İşlem | Açıklama |
ControlTemplate.getNoTemplateObject()
|
None
|
Uygulama bunu kontrol, kontrol, kullanıcı ve uygulama ancak kullanıcı onunla etkileşim kuramaz. |
ToggleTemplate
|
BooleanAction
|
Etkin ve devre dışı durumları arasında geçiş yapabilen bir kontrolü temsil eder
eyaletler. BooleanAction nesnesi, değişen bir alan içeriyor
olarak, kullanıcı denetime dokunduğunda istenen yeni durumu temsil eder.
|
RangeTemplate
|
FloatAction
|
Belirtilen min, maks. ve adım değerlerine sahip bir kaydırma çubuğu widget'ını gösterir. Zaman
Kullanıcı kaydırma çubuğuyla etkileşimde bulunursa yeni bir FloatAction gönderin
nesnesini güncellenmiş değerle uygulamaya geri döndürmenizi sağlar.
|
ToggleRangeTemplate
|
BooleanAction, FloatAction
|
Bu şablon, ToggleTemplate ve
RangeTemplate . Kaydırma çubuğunun yanı sıra dokunma etkinliklerini de destekler.
Örneğin kısılabilir ışıkları kontrol edebilirler.
|
TemperatureControlTemplate
|
ModeAction, BooleanAction, FloatAction
|
Bu şablon, önceki işlemleri kapsüllemenin yanı sıra Kullanıcı ısıtma, soğutma, ısıtma/soğutma, eko veya kapalı gibi bir mod ayarlar. |
StatelessTemplate
|
CommandAction
|
Dokunma yeteneği sağlayan ancak durumu ancak kızılötesi bir televizyon gibi belirlenemiyor. Bunu kullanabilirsiniz kontrolün toplamı olan rutin veya makroyu tanımlamak için kullanılan şablon ve durum değişiklikleri. |
Bu bilgileri kullanarak denetimi oluşturabilirsiniz:
- Şunu kullanın:
Control.StatelessBuilder
oluşturucu sınıfını kullanın. - Şunu kullanın:
Control.StatefulBuilder
oluşturucu sınıfını kullanmanız gerekir.
Örneğin, bir akıllı ampulü ve bir termostatı kontrol etmek için aşağıdakini ekleyin
MyCustomControlService
sabit değerleri:
Kotlin
private const val LIGHT_ID = 1234 private const val LIGHT_TITLE = "My fancy light" private const val LIGHT_TYPE = DeviceTypes.TYPE_LIGHT private const val THERMOSTAT_ID = 5678 private const val THERMOSTAT_TITLE = "My fancy thermostat" private const val THERMOSTAT_TYPE = DeviceTypes.TYPE_THERMOSTAT class MyCustomControlService : ControlsProviderService() { ... }
Java
public class MyCustomJavaControlService extends ControlsProviderService { private final int LIGHT_ID = 1337; private final String LIGHT_TITLE = "My fancy light"; private final int LIGHT_TYPE = DeviceTypes.TYPE_LIGHT; private final int THERMOSTAT_ID = 1338; private final String THERMOSTAT_TITLE = "My fancy thermostat"; private final int THERMOSTAT_TYPE = DeviceTypes.TYPE_THERMOSTAT; ... }
Kontroller için yayıncılar oluşturma
Kontrolü oluşturduktan sonra bir yayıncıya ihtiyacı vardır. Yayıncı,
kontrol varlığının sistem kullanıcı arayüzü. ControlsProviderService
sınıfı
uygulama kodunuzda geçersiz kılmanız gereken iki yayıncı yöntemi vardır:
createPublisherForAllAvailable()
: oluştururPublisher
kullandığınızdan emin olun.Control.StatelessBuilder()
kullan kullanarakControl
nesne oluşturabilirsiniz.createPublisherFor()
: Belirtilen denetimlerin listesi için birPublisher
oluşturur, dize tanımlayıcılarına göre tanımlanır. Şunlar içinControl.StatefulBuilder
kullanın: buControl
nesnesini oluşturur, çünkü yayıncının her bir kontrole dokunun.
Yayıncıyı oluşturma
Uygulamanız, kontrolleri sistem kullanıcı arayüzüne ilk kez yayınladığında uygulama bunu bilmez.
durumu hakkında bilgi edinin. Durum bilgisine ulaşmak zaman alıcı bir işlem olabilir.
çok sayıda atlama olması gerekir. Şunu kullanın:
createPublisherForAllAvailable()
yöntemini kullanabilirsiniz. Bu yöntem
Her bir kontrolün durumu şu olduğundan Control.StatelessBuilder
derleyici sınıfı
bilinmiyor.
Kontroller Android arayüzünde göründükten sonra kullanıcı favorilerini seçebilir kontrol eder.
Kotlin eş yordamlarını kullanarak ControlsProviderService
oluşturmak için, yeni bir
bağımlılığınız: build.gradle
:
Eski
dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk9:1.6.4" }
Kotlin
dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk9:1.6.4") }
Gradle dosyalarınızı senkronize ettikten sonra aşağıdaki snippet'i Service
createPublisherForAllAvailable()
uygulayın:
Kotlin
class MyCustomControlService : ControlsProviderService() { override fun createPublisherForAllAvailable(): Flow.Publisher= flowPublish { send(createStatelessControl(LIGHT_ID, LIGHT_TITLE, LIGHT_TYPE)) send(createStatelessControl(THERMOSTAT_ID, THERMOSTAT_TITLE, THERMOSTAT_TYPE)) } private fun createStatelessControl(id: Int, title: String, type: Int): Control { val intent = Intent(this, MainActivity::class.java) .putExtra(EXTRA_MESSAGE, title) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) val action = PendingIntent.getActivity( this, id, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) return Control.StatelessBuilder(id.toString(), action) .setTitle(title) .setDeviceType(type) .build() } override fun createPublisherFor(controlIds: List ): Flow.Publisher { TODO() } override fun performControlAction( controlId: String, action: ControlAction, consumer: Consumer ) { TODO() } }
Java
public class MyCustomJavaControlService extends ControlsProviderService { private final int LIGHT_ID = 1337; private final String LIGHT_TITLE = "My fancy light"; private final int LIGHT_TYPE = DeviceTypes.TYPE_LIGHT; private final int THERMOSTAT_ID = 1338; private final String THERMOSTAT_TITLE = "My fancy thermostat"; private final int THERMOSTAT_TYPE = DeviceTypes.TYPE_THERMOSTAT; private boolean toggleState = false; private float rangeState = 18f; private final Map> controlFlows = new HashMap<>(); @NonNull @Override public Flow.Publisher createPublisherForAllAvailable() { List controls = new ArrayList<>(); controls.add(createStatelessControl(LIGHT_ID, LIGHT_TITLE, LIGHT_TYPE)); controls.add(createStatelessControl(THERMOSTAT_ID, THERMOSTAT_TITLE, THERMOSTAT_TYPE)); return FlowAdapters.toFlowPublisher(Flowable.fromIterable(controls)); } @NonNull @Override public Flow.Publisher createPublisherFor(@NonNull List controlIds) { ReplayProcessor updatePublisher = ReplayProcessor.create(); controlIds.forEach(control -> { controlFlows.put(control, updatePublisher); updatePublisher.onNext(createLight()); updatePublisher.onNext(createThermostat()); }); return FlowAdapters.toFlowPublisher(updatePublisher); } }
Sistem menüsünü aşağı doğru kaydırın ve şurada gösterilen Cihaz denetimleri düğmesini bulun: Şekil 4:
Cihaz kontrolleri'ne dokunduğunuzda, seçim yapabileceğiniz ikinci bir ekrana gidersiniz en iyi şekilde yararlanabilirsiniz. Uygulamanızı seçtiğinizde önceki snippet'in Şekil 5'te gösterildiği gibi yeni denetimlerinizi gösteren özel sistem menüsü:
Şimdi, aşağıdaki kodu uygulamanıza ekleyerek createPublisherFor()
yöntemini uygulayın:
Service
:
Kotlin
private val job = SupervisorJob() private val scope = CoroutineScope(Dispatchers.IO + job) private val controlFlows = mutableMapOf>() private var toggleState = false private var rangeState = 18f override fun createPublisherFor(controlIds: List ): Flow.Publisher { val flow = MutableSharedFlow (replay = 2, extraBufferCapacity = 2) controlIds.forEach { controlFlows[it] = flow } scope.launch { delay(1000) // Retrieving the toggle state. flow.tryEmit(createLight()) delay(1000) // Retrieving the range state. flow.tryEmit(createThermostat()) } return flow.asPublisher() } private fun createLight() = createStatefulControl( LIGHT_ID, LIGHT_TITLE, LIGHT_TYPE, toggleState, ToggleTemplate( LIGHT_ID.toString(), ControlButton( toggleState, toggleState.toString().uppercase(Locale.getDefault()) ) ) ) private fun createThermostat() = createStatefulControl( THERMOSTAT_ID, THERMOSTAT_TITLE, THERMOSTAT_TYPE, rangeState, RangeTemplate( THERMOSTAT_ID.toString(), 15f, 25f, rangeState, 0.1f, "%1.1f" ) ) private fun createStatefulControl(id: Int, title: String, type: Int, state: T, template: ControlTemplate): Control { val intent = Intent(this, MainActivity::class.java) .putExtra(EXTRA_MESSAGE, "$title $state") .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) val action = PendingIntent.getActivity( this, id, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) return Control.StatefulBuilder(id.toString(), action) .setTitle(title) .setDeviceType(type) .setStatus(Control.STATUS_OK) .setControlTemplate(template) .build() } override fun onDestroy() { super.onDestroy() job.cancel() }
Java
@NonNull @Override public Flow.PublishercreatePublisherFor(@NonNull List controlIds) { ReplayProcessor updatePublisher = ReplayProcessor.create(); controlIds.forEach(control -> { controlFlows.put(control, updatePublisher); updatePublisher.onNext(createLight()); updatePublisher.onNext(createThermostat()); }); return FlowAdapters.toFlowPublisher(updatePublisher); } private Control createStatelessControl(int id, String title, int type) { Intent intent = new Intent(this, MainActivity.class) .putExtra(EXTRA_MESSAGE, title) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent action = PendingIntent.getActivity( this, id, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); return new Control.StatelessBuilder(id + "", action) .setTitle(title) .setDeviceType(type) .build(); } private Control createLight() { return createStatefulControl( LIGHT_ID, LIGHT_TITLE, LIGHT_TYPE, toggleState, new ToggleTemplate( LIGHT_ID + "", new ControlButton( toggleState, String.valueOf(toggleState).toUpperCase(Locale.getDefault()) ) ) ); } private Control createThermostat() { return createStatefulControl( THERMOSTAT_ID, THERMOSTAT_TITLE, THERMOSTAT_TYPE, rangeState, new RangeTemplate( THERMOSTAT_ID + "", 15f, 25f, rangeState, 0.1f, "%1.1f" ) ); } private Control createStatefulControl(int id, String title, int type, T state, ControlTemplate template) { Intent intent = new Intent(this, MainActivity.class) .putExtra(EXTRA_MESSAGE, "$title $state") .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent action = PendingIntent.getActivity( this, id, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); return new Control.StatefulBuilder(id + "", action) .setTitle(title) .setDeviceType(type) .setStatus(Control.STATUS_OK) .setControlTemplate(template) .build(); }
Bu örnekte, createPublisherFor()
yöntemi sahte bir
uygulamanızla iletişim kurma:
alma ve bu durumu sisteme iletme.
createPublisherFor()
yöntemi, aşağıdaki koşulu karşılamak için Kotlin eş yordamlarını ve akışlarını kullanır
aşağıdaki işlemleri yaparak gerekli Reactive Streams API'sini isteyin:
Flow
oluşturur.- Bir saniye bekler.
- Akıllı ışığın durumunu oluşturur ve yayar.
- Bir saniye daha bekler.
- Termostatın durumunu oluşturur ve yayınlar.
İşlemleri işleme
performControlAction()
yöntemi, kullanıcı bir
yayınlanmış kontrolde bulabilirsiniz. Gönderilen ControlAction
türü, işlemi belirler.
Verilen denetim için uygun işlemi gerçekleştirip durumu güncelleyin
cihazın Android kullanıcı arayüzünde görebilirsiniz.
Örneği tamamlamak için Service
öğenize aşağıdakileri ekleyin:
Kotlin
override fun performControlAction( controlId: String, action: ControlAction, consumer: Consumer) { controlFlows[controlId]?.let { flow -> when (controlId) { LIGHT_ID.toString() -> { consumer.accept(ControlAction.RESPONSE_OK) if (action is BooleanAction) toggleState = action.newState flow.tryEmit(createLight()) } THERMOSTAT_ID.toString() -> { consumer.accept(ControlAction.RESPONSE_OK) if (action is FloatAction) rangeState = action.newValue flow.tryEmit(createThermostat()) } else -> consumer.accept(ControlAction.RESPONSE_FAIL) } } ?: consumer.accept(ControlAction.RESPONSE_FAIL) }
Java
@Override public void performControlAction(@NonNull String controlId, @NonNull ControlAction action, @NonNull Consumerconsumer) { ReplayProcessor processor = controlFlows.get(controlId); if (processor == null) return; if (controlId.equals(LIGHT_ID + "")) { consumer.accept(ControlAction.RESPONSE_OK); if (action instanceof BooleanAction) toggleState = ((BooleanAction) action).getNewState(); processor.onNext(createLight()); } if (controlId.equals(THERMOSTAT_ID + "")) { consumer.accept(ControlAction.RESPONSE_OK); if (action instanceof FloatAction) rangeState = ((FloatAction) action).getNewValue() processor.onNext(createThermostat()); } }
Uygulamayı çalıştırın, Cihaz kontrolleri menüsüne erişin, ışığınızı ve termostat kontrollerine dokunun.