Özel cihazlar için tarif defteri

Bu tarif defteri, geliştiricilerin ve sistem entegratörlerinin kendi özel alanlarını geliştirmelerine ve cihaz çözümü. Özel cihazlara uygun çözümler bulmak için "Nasıl yapılır?" tariflerimizi izleyin ve bunları kontrol etmenizi sağlar. Bu tarif defteri, halihazırda özel bir planı olan geliştiriciler için daha çok işe yarar. veya kullanmaya yeni başlıyorsanız Özel cihazlar genel bakış bölümüne bakın.

Özel Ana Ekran uygulamaları

Bu yemek tarifleri, Android Home'un yerini alacak bir uygulama geliştiriyorsanız işinize yarar ve Başlatıcı'yı tıklayın.

Ana ekran uygulaması olun

Kullanıma sunulması için uygulamanızı cihazın ana ekran uygulaması olarak ayarlayabilirsiniz otomatik olarak güncellenir. Ayrıca, Ana Sayfa'yı Kilitliyken, izin verilenler listesine eklenmiş uygulamanızı ön plana getiren düğme görev moduna girebilirsiniz.

Tüm ana ekran uygulamaları, CATEGORY_HOME amaç kategorisini işler. sistemin ana ekran uygulamasını tanıma şeklidir. Varsayılan ana ekran uygulaması olmak için bir uygulama ayarlayın tercih edilen Home intent işleyicisi olarak uygulamanızın etkinliklerini DevicePolicyManager.addPersistentPreferredActivity() aşağıdaki örnekte gösterildiği gibi:

Kotlin

// Create an intent filter to specify the Home category.
val filter = IntentFilter(Intent.ACTION_MAIN)
filter.addCategory(Intent.CATEGORY_HOME)
filter.addCategory(Intent.CATEGORY_DEFAULT)

// Set the activity as the preferred option for the device.
val activity = ComponentName(context, KioskModeActivity::class.java)
val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE)
        as DevicePolicyManager
dpm.addPersistentPreferredActivity(adminName, filter, activity)

Java

// Create an intent filter to specify the Home category.
IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
filter.addCategory(Intent.CATEGORY_HOME);
filter.addCategory(Intent.CATEGORY_DEFAULT);

// Set the activity as the preferred option for the device.
ComponentName activity = new ComponentName(context, KioskModeActivity.class);
DevicePolicyManager dpm =
    (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
dpm.addPersistentPreferredActivity(adminName, filter, activity);

Yine de amaç filtresini bildirmeniz gerekir aşağıdaki XML snippet'inde gösterildiği gibi manifest dosyanızda:

<activity
        android:name=".KioskModeActivity"
        android:label="@string/kiosk_mode"
        android:launchMode="singleInstance"
        android:excludeFromRecents="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.HOME"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

Genellikle başlatıcı uygulamanızın Genel Bakış ekranında görünmesini istemezsiniz. Ancak, excludeFromRecents öğesini etkinlik beyanı çünkü Android’in Launcher başlangıçta etkinliği olması gerekir.

Ayrı görevleri göster

FLAG_ACTIVITY_NEW_TASK, şunun için yararlı bir işaret olabilir: her yeni görev aşağıda ayrı bir öğe olarak göründüğünden, başlatıcı türü Genel bakış ekranı. Genel Bakış ekranındaki görevler hakkında daha fazla bilgi için Son kullanılanlar Ekran.

Herkese açık kiosk'lar

Bu tarifler, kamuya açık alanlarda gözetimsiz cihazlarda oldukça iyidir ancak birçok özel cihaz kullanıcısının işlerine odaklanmasına yardımcı oluyor.

Cihazı kilitleyin

Cihazların amaçlarına uygun şekilde kullanıldığından emin olmak için tablo 1'de listelenen kullanıcı kısıtlamalarına tabidir.

Tablo 1. Kiosk cihazlar için kullanıcı kısıtlamaları
Kullanıcı kısıtlaması Açıklama
DISALLOW_FACTORY_RESET Cihazın kullanıcısının cihazı fabrika varsayılan ayarlarına sıfırlamasını engeller. Tümüyle yönetilen cihazların yöneticileri ve birincil kullanıcı bunu ayarlayabilir olur.
DISALLOW_SAFE_BOOT Cihaz kullanıcısının cihazı başlatmasını engeller güvenli mod sistem uygulamanızı otomatik olarak başlatmaz. Tamamen yönetilen cihazlar ve birincil kullanıcı bu kısıtlamayı ayarlayabilir.
DISALLOW_MOUNT_PHYSICAL_MEDIA Cihaz kullanıcısının oluşturabileceği depolama birimlerini eklemesini engeller ekleyebilirsiniz. Tümüyle yönetilen cihazların ve birincil kullanıcının yöneticileri bu kısıtlamayı belirleyebilirsiniz.
DISALLOW_ADJUST_VOLUME Cihazın sesini kapatır ve cihaz kullanıcısının sesi değiştirmesini önler ses düzeyi ve titreşim ayarlarına gidin. Kiosk'unuzda ses kullanılmasının gerekmediğinden emin olun medya oynatma veya erişilebilirlik özellikleri için. Tümüyle yönetilen yöneticileri cihazlar, birincil kullanıcı, ikincil kullanıcılar ve iş profilleri bu ayarı olur.
DISALLOW_ADD_USER Cihaz kullanıcısının ikincil kullanıcılar veya kısıtlanmış kullanıcılar için geçerlidir. Sistem bu kullanıcı kısıtlamasını tümüyle yönetilen cihazlarda, ancak silinmiş olabilir. Tamamen yönetilen cihazlar ve birincil kullanıcı bu kısıtlamayı ayarlayabilir.

Aşağıdaki snippet'te, kısıtlamaları nasıl ayarlayabileceğiniz gösterilmektedir:

Kotlin

// If the system is running in lock task mode, set the user restrictions
// for a kiosk after launching the activity.
arrayOf(
        UserManager.DISALLOW_FACTORY_RESET,
        UserManager.DISALLOW_SAFE_BOOT,
        UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
        UserManager.DISALLOW_ADJUST_VOLUME,
        UserManager.DISALLOW_ADD_USER).forEach { dpm.addUserRestriction(adminName, it) }

Java

// If the system is running in lock task mode, set the user restrictions
// for a kiosk after launching the activity.
String[] restrictions = {
    UserManager.DISALLOW_FACTORY_RESET,
    UserManager.DISALLOW_SAFE_BOOT,
    UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
    UserManager.DISALLOW_ADJUST_VOLUME,
    UserManager.DISALLOW_ADD_USER};

for (String restriction: restrictions) dpm.addUserRestriction(adminName, restriction);

Uygulamanız yönetici modundayken bu kısıtlamaları kaldırmak isteyebilirsiniz. BT yöneticileri, cihaz bakımı için bu özellikleri kullanmaya devam edebilir. Temizlemek için kısıtlama, çağrı DevicePolicyManager.clearUserRestriction().

Hata iletişim kutularını gizle

Perakende satış gösterileri veya kamuya açık bilgiler gibi bazı ortamlarda görüntülendiğinde, kullanıcılara hata iletişim kutuları göstermek istemeyebilirsiniz. Android 9.0 (API) sürümünde düzeyi 28) veya daha yüksek olursa, kilitlenme sorunu için sistem hatası iletişim kutularını gizleyebilirsiniz yanıt vermeyen uygulamalara DISALLOW_SYSTEM_ERROR_DIALOGS kullanıcısı olur. Sistem, yanıt vermeyen uygulamaları, cihaz kullanıcısı kapanmış gibi yeniden başlatır iletişim kutusundan seçeceğiz. Aşağıdaki örnekte bunu nasıl yapabileceğiniz gösterilmektedir:

Kotlin

override fun onEnabled(context: Context, intent: Intent) {
    val dpm = getManager(context)
    val adminName = getWho(context)

    dpm.addUserRestriction(adminName, UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS)
}

Java

public void onEnabled(Context context, Intent intent) {
  DevicePolicyManager dpm = getManager(context);
  ComponentName adminName = getWho(context);

  dpm.addUserRestriction(adminName, UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS);
}

Birincil veya ikincil kullanıcının yöneticisi bu kısıtlamayı ayarlarsa sistem yalnızca söz konusu kullanıcının hata iletişim kutularını gizler. Tümüyle yönetilen bir bu kısıtlamayı ayarladığında sistem, tüm kullanıcıların iletişim kutularını gizler.

Ekranı açık tutma

Bir kiosk oluşturuyorsanız cihazın şu anda gezinmesini uyku modundan çıkarır. Ekle FLAG_KEEP_SCREEN_ON düzen işaretini uygulamanızın penceresi aşağıdaki örnekte gösterildiği gibidir:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // Keep the screen on and bright while this kiosk activity is running.
    window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // Keep the screen on and bright while this kiosk activity is running.
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}

Cihazın AC, USB veya kablosuz bir güç kaynağına takılı olduğundan emin olmak isteyebilirsiniz şarj cihazı. Pil değişikliği yayınlarına kaydolup BatteryManager hizmetini kullanın değerlerini kullanabilirsiniz. Hatta bir BT departmanına uzaktan uyarı da yönetici ile iletişime geçin. Adım adım talimatlar için şu adresi okuyun: Pil Seviyesini ve Şarj Seviyesini İzleme Eyalet.

Ayrıca, STAY_ON_WHILE_PLUGGED_IN genel ayar olan genel ayar, cihazın güç kaynağına bağlıyken uyanık kalmasını sağlar. Android 6.0 (API düzeyi 23) veya sonraki sürümlere sahip tam olarak yönetilen cihazların yöneticileri gösterildiği gibi DevicePolicyManager.setGlobalSetting() numaralı telefonu ara aşağıdaki örnekte:

Kotlin

val pluggedInto = BatteryManager.BATTERY_PLUGGED_AC or
        BatteryManager.BATTERY_PLUGGED_USB or
        BatteryManager.BATTERY_PLUGGED_WIRELESS
dpm.setGlobalSetting(adminName,
        Settings.Global.STAY_ON_WHILE_PLUGGED_IN, pluggedInto.toString())

Java

int pluggedInto = BatteryManager.BATTERY_PLUGGED_AC |
    BatteryManager.BATTERY_PLUGGED_USB |
    BatteryManager.BATTERY_PLUGGED_WIRELESS;
dpm.setGlobalSetting( adminName,
    Settings.Global.STAY_ON_WHILE_PLUGGED_IN, String.valueOf(pluggedInto));

Uygulama paketleri

Bu bölümde, uygulamaları özel cihazlara verimli bir şekilde yüklemek için kullanılabilecek tarifler yer alır.

Uygulama paketlerini önbelleğe al

Paylaşılan bir cihazın tüm kullanıcılarının ortak bir uygulama grubu varsa mümkün olduğunca uygulama indirmekten kaçınmalısınız. Basit bir belirli bir kullanıcı grubuyla paylaşılan cihazlarda (ör. vardiya çalışanları, Android 9.0 (API düzeyi 28) veya sonraki sürümlerde uygulamayı önbelleğe alabilir paketleri (APK'lar) ekleyebilirsiniz.

Önbelleğe alınmış bir APK'nın (cihazda zaten yüklü olan) yüklenmesi iki aşamadan oluşur:

  1. Tümüyle yönetilen bir cihazın (veya yetki verilmiş bir kullanıcının) yönetici bileşeni.bkz. Aşağıdaki gibi), cihazda saklanacak APK'ların listesini ayarlar.
  2. İlişkili ikincil kullanıcıların (veya yetki verdikleri kullanıcıların) yönetici bileşenleri: önbelleğe alınan APK'yı kullanıcı adına yüklemelidir. Tümüyle yönetilen birincil kullanıcı veya ilişkili bir iş profili (ya da yetki verilmiş kullanıcılar) gerektiğinde önbelleğe alınan uygulamayı da yükleyebilir.

Cihazda saklanacak APK'ların listesini ayarlamak için yönetici arar DevicePolicyManager.setKeepUninstalledPackages(). Bu yöntem, APK'nın cihazda yüklü olup olmadığını kontrol etmez. Bu yöntem, APK'nın cihazda yüklü olup olmadığını kontrol etmez. ihtiyaç duymadan hemen önce uygulamayı yüklemek istiyorsanız İş Listesi’ndeki paket servislerini kullanarak DevicePolicyManager.getKeepUninstalledPackages(). Değişiklikleri bildirmek için setKeepUninstalledPackages() numaralı telefonu aradıktan sonra veya ikincil Kullanıcı silindiğinde sistem, önbelleğe alınmış ve artık gerekli olmayan tüm APK'ları siler.

Önbelleğe alınmış bir APK yüklemek için şunu çağırın: DevicePolicyManager.installExistingPackage(). Bu yöntem yalnızca sistemin önceden önbelleğe aldığı uygulamaları yükleyebilir. Sizin özel cihaz çözümünün (veya cihazın kullanıcısının) öncelikle uygulamayı işlemi gerçekleştirmeniz gerekir.

Aşağıdaki örnek, bu API çağrılarını Tümüyle yönetilen bir cihaz ve ikincil kullanıcı:

Kotlin

// Set the package to keep. This method assumes that the package is already
// installed on the device by managed Google Play.
val cachedAppPackageName = "com.example.android.myapp"
dpm.setKeepUninstalledPackages(adminName, listOf(cachedAppPackageName))

// ...

// The admin of a secondary user installs the app.
val success = dpm.installExistingPackage(adminName, cachedAppPackageName)

Java

// Set the package to keep. This method assumes that the package is already
// installed on the device by managed Google Play.
String cachedAppPackageName = "com.example.android.myapp";
List<String> packages = new ArrayList<String>();
packages.add(cachedAppPackageName);
dpm.setKeepUninstalledPackages(adminName, packages);

// ...

// The admin of a secondary user installs the app.
boolean success = dpm.installExistingPackage(adminName, cachedAppPackageName);

Uygulamalara yetki verme

Uygulamaları önbelleğe almayı yönetmesi için başka bir uygulamaya yetki verebilirsiniz. Bu işlemi gerçekleştirmek için çözümünüzün özelliklerini ayırın veya BT yöneticilerine, kullanıyor. Yetki verilmiş uygulama, yöneticiyle aynı izinlere sahip olur bir bileşenidir. Örneğin, ikincil bir kullanıcının yöneticisindeki uygulama için yetki verilmiş bir kullanıcı installExistingPackage(), ancak setKeepUninstalledPackages() aranamıyor.

Yetki verilmiş bir arama yapmak için DevicePolicyManager.setDelegatedScopes() ve dahil et DELEGATION_KEEP_UNINSTALLED_PACKAGES kullanabilirsiniz. Aşağıdaki örnekte, farklı bir uygulamayı nasıl yapılandırabileceğiniz yetki verilen kullanıcı:

Kotlin

var delegatePackageName = "com.example.tools.kept_app_assist"

// Check that the package is installed before delegating.
try {
    context.packageManager.getPackageInfo(delegatePackageName, 0)
    dpm.setDelegatedScopes(
            adminName,
            delegatePackageName,
            listOf(DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES))
} catch (e: PackageManager.NameNotFoundException) {
    // The delegate app isn't installed. Send a report to the IT admin ...
}

Java

String delegatePackageName = "com.example.tools.kept_app_assist";

// Check that the package is installed before delegating.
try {
  context.getPackageManager().getPackageInfo(delegatePackageName, 0);
  dpm.setDelegatedScopes(
      adminName,
      delegatePackageName,
      Arrays.asList(DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES));
} catch (PackageManager.NameNotFoundException e) {
  // The delegate app isn't installed. Send a report to the IT admin ...
}

Her şey yolunda giderse yetki verilmiş uygulama ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED devreye girer ve delege haline gelir. Uygulama, bu kılavuzdaki yöntemleri çağırabilir sanki o kişi veya profilin sahibi gibi. Ararken DevicePolicyManager yöntemde, yetki verilen kullanıcı, yönetici için null tarihinde doğrulama yapar. bileşen bağımsız değişkeninin önüne geçer.

Uygulama paketlerini yükleme

Bazen, yerel olarak önbelleğe alınmış özel bir uygulamayı, olanak tanır. Örneğin, bir amaca özel ayrılmış cihazlar genellikle veya bant genişliğinin sınırlı olduğu ortamlarda veya internet bağlantısının olmadığı alanlarda Sizin özel cihaz çözümü, müşterilerinizin bant genişliğine dikkat etmelidir. Sizin başka bir uygulama paketinin (APK) yüklenmesini sağlayabilir, bunun için PackageInstaller sınıf.

Her uygulama APK yükleyebilir ancak tümüyle yönetilen cihazlardaki yöneticiler bunları yükleyebilir. Paketleri kullanıcı etkileşimi olmadan yükleme (veya kaldırma). Yönetici, Cihaz, ilişkilendirilmiş ikincil kullanıcı veya ilişkili bir iş profili. Şu tarihten sonra: yükleme tamamlandığında sistem, tüm cihaz kullanıcılarına bakın. Bildirimde, cihaz kullanıcılarına uygulamanın yüklendiği (veya tarafından gerçekleştirilir)

Tablo 2. Paket yüklemeyi destekleyen Android sürümleri kullanıcı etkileşimi olmadan
Android sürümü Yükleme ve kaldırma için yönetici bileşeni
Android 9.0 (API düzeyi 28) veya sonraki sürümler İlişkili ikincil kullanıcılar ve iş profilleri (her ikisi de tümüyle yönetilen cihazlarda) cihazlar
Android 6.0 (API düzeyi 23) veya sonraki sürümler Tümüyle yönetilen cihazlar

APK'nın bir veya daha fazla kopyasını özel cihazlara nasıl dağıttığınız cihazlar birbirinden ne kadar uzak olduğuna ve birbirlerinden birbirinden farklıdır. Çözümünüz güvenlikle ilgili en iyi uygulamalara uygun olmalıdır .

Sıraya alınan bir oturum oluşturmak için PackageInstaller.Session aracını kullanabilirsiniz veya daha fazla APK'yı yükleyebilirsiniz. Aşağıdaki örnekte, etkinliğindeki (singleTop modu) geri bildirim vermek yerine bir hizmet veya yayın alıcı:

Kotlin

// First, create a package installer session.
val packageInstaller = context.packageManager.packageInstaller
val params = PackageInstaller.SessionParams(
        PackageInstaller.SessionParams.MODE_FULL_INSTALL)
val sessionId = packageInstaller.createSession(params)
val session = packageInstaller.openSession(sessionId)

// Add the APK binary to the session. The APK is included in our app binary
// and is read from res/raw but file storage is a more typical location.
// The I/O streams can't be open when installation begins.
session.openWrite("apk", 0, -1).use { output ->
    getContext().resources.openRawResource(R.raw.app).use { input ->
        input.copyTo(output, 2048)
    }
}

// Create a status receiver to report progress of the installation.
// We'll use the current activity.
// Here we're requesting status feedback to our Activity but this can be a
// service or broadcast receiver.
val intent = Intent(context, activity.javaClass)
intent.action = "com.android.example.APK_INSTALLATION_ACTION"
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
val statusReceiver = pendingIntent.intentSender

// Start the installation. Because we're an admin of a fully managed device,
// there isn't any user interaction.
session.commit(statusReceiver)

Java

// First, create a package installer session.
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);

// Add the APK binary to the session. The APK is included in our app binary
// and is read from res/raw but file storage is a more typical location.
try (
    // These I/O streams can't be open when installation begins.
    OutputStream output = session.openWrite("apk", 0, -1);
    InputStream input = getContext().getResources().openRawResource(R.raw.app);
) {
  byte[] buffer = new byte[2048];
  int n;
  while ((n = input.read(buffer)) >= 0) {
    output.write(buffer, 0, n);
  }
}

// Create a status receiver to report progress of the installation.
// We'll use the current activity.
// Here we're requesting status feedback to our Activity but this can be a
// service or broadcast receiver.
Intent intent = new Intent(context, getActivity().getClass());
intent.setAction("com.android.example.APK_INSTALLATION_ACTION");
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
IntentSender statusReceiver = pendingIntent.getIntentSender();

// Start the installation. Because we're an admin of a fully managed device,
// there isn't any user interaction.
session.commit(statusReceiver);

Oturum, intent'leri kullanarak yükleme hakkında durum geri bildirimi gönderir. Kontrol et her bir intent'in EXTRA_STATUS alanını kullanarak durum. Unutmayın, yöneticiler STATUS_PENDING_USER_ACTION durum güncellemesi Çünkü cihaz kullanıcısının yüklemeyi onaylamasına gerek yoktur.

Uygulamaları kaldırmak için PackageInstaller.uninstall numaralı telefonu arayabilirsiniz. Tümüyle yönetilen cihazların, kullanıcıların ve iş profillerinin yöneticileri paketleri kaldırabilir Desteklenen Android sürümlerini çalıştıran kullanıcı etkileşimi olmadan (bkz. tablo 2).

Sistem güncellemelerini dondur

Android cihazlar sistem ve uygulama için kablosuz (OTA) güncellemeler alır daha fazla bilgi edineceksiniz. Tatil veya e-posta gibi kritik dönemlerde işletim sistemi sürümünü dondurmak özel cihazlar, OTA sistem güncellemelerini 90 dakikaya kadar askıya alabilir. gün. Daha fazla bilgi edinmek için Sistem güncellemelerini yönetme başlıklı makaleyi inceleyin.

Remote Config

Android’in yönetilen yapılandırmaları, BT yöneticilerinin şunları yapmasına olanak tanır: yapılandırabileceğiniz anlamına gelir. Örneğin, uygulamanızı BT için daha yararlı hale getirmek üzere izin verilenler listeleri, ağ ana makineleri veya içerik URL'leri yöneticileri içindir.

Uygulamanız yapılandırmasını açığa çıkarıyorsa belgelerinden faydalanabilirsiniz. Uygulamanızın yapılandırmasını açığa çıkarma ve daha fazla bilgi için Yönetilen yapılandırmaları ayarlama başlıklı makaleyi inceleyin.

Geliştirme kurulumu

Özel cihazlara yönelik çözümünüzü geliştirirken bazen uygulamanızı, fabrika ayarı olmayan tümüyle yönetilen bir cihazın yöneticisi olarak ayarlamanız açısından yararlıdır. sıfırlandı. Tümüyle yönetilen bir cihazın yöneticisini ayarlamak için aşağıdaki adımları uygulayın:

  1. Cihaz politikası denetleyici (DPC) uygulamanızı derleyip cihazınıza yükleyin.
  2. Cihazda hesap olmadığından emin olun.
  3. Android Debug Bridge (adb) kabuğunda aşağıdaki komutu çalıştırın. Siz örnekteki com.example.dpc/.MyDeviceAdminReceiver değerinin uygulamanızın yönetici bileşen adı:

    adb shell dpm set-device-owner com.example.dpc/.MyDeviceAdminReceiver

Müşterilerin çözümünüzü dağıtmasına yardımcı olmak için diğer kayıtlara bakmanız gerekiyor. yöntemleri. Şu işlemler için QR kodu kaydını öneririz: cihazlar.

Ek kaynaklar

Bir amaca özel ayrılmış cihazlar hakkında daha fazla bilgi edinmek için aşağıdaki dokümanları okuyun: