إدارة التركيز الصوتي

يمكن لتطبيقين أو أكثر من تطبيقات Android تشغيل الصوت على نفس مصدر الإخراج في الوقت نفسه، ويمزج النظام كل شيء معًا. في حين أن هذا من الناحية الفنية، فقد يؤدي ذلك إلى تفاقم حالة المستخدم بشكل كبير. لتجنب كل تطبيق موسيقى واحد يتم تشغيله في الوقت نفسه، يقدّم Android فكرة الصوت التركيز. يمكن لتطبيق واحد فقط الاحتفاظ بالتركيز على الصوت في كل مرة.

يجب أن يطلب التطبيق التركيز على الصوت عندما يحتاج إلى إصدار صوت. عندما يكون التركيز، فيمكنه تشغيل الصوت. ولكن بعد الحصول على تركيز صوتي، قد لا الاحتفاظ بها حتى تنتهي من اللعب. يمكن لتطبيق آخر أن يطلب التركيز، مما بشكل استباقي تعليق التركيز على الصوت. إذا حدث ذلك، من المفترض أن يتوقف تطبيقك مؤقتًا. تشغيل الصوت أو خفضه للسماح للمستخدمين بسماع مصدر الصوت الجديد بسهولة أكبر

قبل الإصدار Android 12 (المستوى 31 لواجهة برمجة التطبيقات)، لا يدير النظام تركيز الصوت. وبالتالي، بينما ننصح مطوّري التطبيقات بالالتزام بإرشادات التركيز الصوتي إذا استمرّ تشغيل أحد التطبيقات بصوت عالٍ حتى بعد فقدان ميزة التركيز الصوتي على أحد الأجهزة إذا كان الجهاز يعمل بالإصدار 11 من نظام التشغيل Android (المستوى 30 لواجهة برمجة التطبيقات) أو بإصدار أقدم، لا يمكن للنظام منعه. ومع ذلك، ينتج عن هذا السلوك في التطبيق تجربة سيئة للمستخدم وقد يؤدي غالبًا إلى من المستخدمين إلغاء تثبيت التطبيق الذي يعمل على نحو غير صحيح.

يجب أن يدير تطبيق الصوت التصميم جيدًا تركيز الصوت وفقًا لهذه القواعد إرشاداتنا:

  • يجب الاتصال بـ requestAudioFocus() مباشرةً قبل بدء التشغيل والتأكّد من أنّ يعود الاتصال AUDIOFOCUS_REQUEST_GRANTED إجراء مكالمة مع requestAudioFocus() في معاودة الاتصال "onPlay()" لجلسة الوسائط.

  • عندما يلتقط تطبيق آخر تركيزًا صوتيًا، أو يتوقف التشغيل أو توقفه مؤقتًا، أو يتوقف عن التشغيل (أي خفض مستوى الصوت.

  • عند إيقاف التشغيل (على سبيل المثال، عندما لا يكون لدى التطبيق أي شيء لتشغيله) التخلي عن التركيز الصوتي. ليس على تطبيقك التخلّي عن ميزة "التركيز على الصوت" إذا كان المستخدم يوقف التشغيل مؤقتًا ولكنه قد يستأنف التشغيل لاحقًا.

  • استخدام AudioAttributes لوصف ونوع الصوت الذي يتم تشغيله في تطبيقك. على سبيل المثال، في التطبيقات التي تشغِّل الكلام، التحديد CONTENT_TYPE_SPEECH

يتم التعامل مع ميزة "التركيز الصوتي" بشكل مختلف حسب إصدار Android الذي قيد التشغيل:

Android 12 (المستوى 31 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث
يدير النظام ميزة التركيز الصوتي. يفرض النظام تشغيل الصوت من تلاشي التطبيق عندما يطلب تطبيق آخر التركيز على الصوت. النظام وكتم أيضًا تشغيل الصوت عند تلقّي مكالمة واردة.
Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) إلى Android 11 (المستوى 30 لواجهة برمجة التطبيقات)
لا يدير النظام التركيز على الصوت، ولكنه يتضمّن بعض التغييرات التي تمت تم طرحه بدءًا من الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات).
الإصدار 7.1 من نظام التشغيل Android (المستوى 25 من واجهة برمجة التطبيقات) والإصدارات الأقدم
لا يدير النظام ميزة "التركيز الصوتي"، وتدير التطبيقات ميزة "التركيز الصوتي" باستخدام requestAudioFocus() أو abandonAudioFocus()

ميزة "تركيز الصوت" في الإصدار 12 من نظام التشغيل Android والإصدارات الأحدث

يجب عدم تشغيل الصوت بعد أن يفقد أي تطبيقات وسائط أو ألعاب تستخدم ميزة "التركيز على الصوت". التركيز. في Android 12 (المستوى 31 لواجهة برمجة التطبيقات) والإصدارات الأحدث، يفرض النظام ذلك السلوك. عندما يطلب أحد التطبيقات التركيز على الصوت بينما يتم التركيز على تطبيق آخر قيد التشغيل، يفرض النظام التلاشي على التطبيق قيد التشغيل. إن إضافة كما أن التلاشي للخارج يوفر انتقالاً أكثر سلاسة عند الانتقال من تطبيق إلى آخر.

ويحدث سلوك التلاشي هذا عند استيفاء الشروط التالية:

  1. يستوفي التطبيق الأول الذي يتم تشغيله حاليًا جميع المعايير التالية:

  2. يطلب تطبيق آخر التركيز على الصوت باستخدام "AudioManager.AUDIOFOCUS_GAIN".

عند استيفاء هذه الشروط، يتلاشى النظام الصوتي للتطبيق الأول. في جلسة المعمل، نهاية التلاشي، يرسل النظام إشعارًا إلى التطبيق الأول لفقدان التركيز. ويظل المشغّلون مكتومين الصوت إلى أن يطلب التطبيق التركيز على الصوت مرة أخرى.

السلوكيات الحالية للتركيز الصوتي

يجب أن تطّلع أيضًا على هذه الحالات الأخرى التي تتضمّن تبديلاً في الصوت. التركيز.

تجنب التداخل التلقائي

تجنب التداخل التلقائي (خفض مستوى الصوت مؤقتًا لتطبيق واحد بحيث يمكن سماع شيء آخر بوضوح) في Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات).

ولن تضطر إلى تنفيذ نمط التداخل مع النظام من خلال تطبيقك.

يحدث تجنُّب التداخل مع أصوات أخرى أيضًا عندما يلفت إشعار صوتي التركيز. من تطبيق تشغيل. تتم مزامنة بدء تشغيل الإشعارات. مع نهاية منحدر التحايل.

يحدث تجنب التداخل التلقائي عند استيفاء الشروط التالية:

  1. يستوفي التطبيق الأول المشغَّل حاليًا جميع المعايير التالية:

  2. يطلب تطبيق ثانٍ التركيز الصوتي مع AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK

عند استيفاء هذه الشروط، يقلل نظام الصوت جميع المشغلات النشطة التطبيق الأول بينما يركز التطبيق الثاني. عند إغلاق التطبيق الثاني التركيز، فإنه يتخلص منها. لا يتم إشعار التطبيق الأول عندما يفقد التركيز، لذلك لا يلزم القيام بأي شيء.

يُرجى العلم أنّه لا يتم تطبيق تجنّب التداخل مع أصوات أخرى عندما يستمع المستخدم إلى الحركات. محتوى الكلام، لأن المستخدم قد يفوته بعض البرنامج. على سبيل المثال: لا يتم استبعاد الإرشاد الصوتي لاتجاهات القيادة.

كتم تشغيل الصوت الحالي للمكالمات الهاتفية الواردة

لا تعمل بعض التطبيقات بشكل صحيح وتستمر في تشغيل الصوت أثناء المكالمات الهاتفية. يجبر هذا الموقف المستخدم على العثور على التطبيق المسيء وكتم صوته أو إنهائه في من أجل سماع نداءه. لمنع ذلك، يمكن للنظام كتم الصوت من أجهزة التطبيقات أثناء تلقي مكالمة واردة. يستدعي النظام هذه الميزة عند عند تلقّي مكالمة هاتفية واردة واستيفاء أحد التطبيقات الشروط التالية:

  • يحتوي التطبيق على AudioAttributes.USAGE_MEDIA أو سمة الاستخدام AudioAttributes.USAGE_GAME
  • طلب التطبيق بنجاح أي تركيز صوتي (أي زيادة التركيز) ويجري التشغيل. الصوت.

في حال استمرار تشغيل أحد التطبيقات أثناء المكالمة، سيتم كتم صوته حتى تنتهي المكالمة. ومع ذلك، إذا بدأ تشغيل أحد التطبيقات أثناء المكالمة، فلن يتم إيقاف مكتوم الصوت على افتراض أن المستخدم بدأ التشغيل عن قصد.

ميزة "تركيز الصوت" على إصدارات Android 8.0 إلى Android 11

بدءًا من Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، عند استدعاء requestAudioFocus() يجب توفير مَعلمة AudioFocusRequest. AudioFocusRequest يحتوي على معلومات عن سياق الصوت وإمكانات تطبيقك. تشير رسالة الأشكال البيانية يستخدم هذا النظام هذه المعلومات لإدارة التقاط وفقدان التركيز الصوتي تلقائيًا. لتحرير التركيز الصوتي، يمكنك استدعاء الطريقة. abandonAudioFocusRequest() والذي يأخذ أيضًا AudioFocusRequest كوسيطة. استخدام القيم نفسها يحدث AudioFocusRequest عند طلب التركيز وإلغاء التركيز.

لإنشاء AudioFocusRequest، استخدِم AudioFocusRequest.Builder نظرًا لأن طلب التركيز يجب نوع الطلب دائمًا، يتم تضمين النوع في الدالة الإنشائية للمنشئ. استخدم طرق الإنشاء لتعيين الحقول الأخرى طلبك.

يجب ملء الحقل FocusGain. فإن جميع الحقول الأخرى اختيارية.

الطريقةملاحظات
setFocusGain() هذا الحقل مطلوب في كل طلب. إنها تأخذ نفس القيم مثل durationHint المستخدم في الاتصال الذي جرى قبل نظام Android 8.0 للاتصال بـ requestAudioFocus(): AUDIOFOCUS_GAIN، AUDIOFOCUS_GAIN_TRANSIENT، AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK أو AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
setAudioAttributes() يصف AudioAttributes حالة الاستخدام لتطبيقك. تشير رسالة الأشكال البيانية يفحصها النظام عندما يلتقط التطبيق تركيزه ويفقد تركيزه. السمات أن تحل محل مفهوم نوع البث في Android 8.0 (المستوى 26 لواجهة برمجة التطبيقات) والإصدارات الأحدث، سيتم إيقاف أنواع البث لأي عملية غير عناصر التحكم في مستوى الصوت. استخدام السمات نفسها في طلب التركيز الذي تستخدمه في مشغِّل الصوت (كما كما هو موضح في المثال الذي يلي هذا الجدول).

استخدِم AudioAttributes.Builder لتحديد ثم استخدم هذه الطريقة لتعيين التصنيفات إلى طلبك.

إذا لم يتم تحديده، سيتم ضبط AudioAttributes تلقائيًا على AudioAttributes.USAGE_MEDIA.

setWillPauseWhenDucked() عندما يطلب تطبيق آخر التركيز باستخدام AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK، لا يحتفظ التطبيق محل التركيز تتلقى عادةً onAudioFocusChange() لأن النظام يمكنه إجراء المحتوى بمفرده. عندما تريد إيقاف التشغيل مؤقتًا بدلاً من من تقليل الصوت، يُرجى الاتصال بـ setWillPauseWhenDucked(true) وإنشاء OnAudioFocusChangeListener، كما هو موضح في قسم تلقائي
setAcceptsDelayedFocusGain() قد يتعذّر طلب التركيز الصوتي عندما يكون التركيز مقفلاً بواسطة تطبيق آخر. تتيح هذه الطريقة تفعيل زيادة التركيز المتأخرة: وهي القدرة للتركيز بشكل غير متزامن عند توفُّره.

لاحظ أن زيادة التركيز المتأخر لا تعمل إلا إذا حددت أيضًا AudioManager.OnAudioFocusChangeListener في طلب الصوت، لأنّ التطبيق يحتاج إلى تلقي معاودة الاتصال لمعرفة أن التركيز قد تم منحه.

setOnAudioFocusChangeListener() لا يكون OnAudioFocusChangeListener مطلوبًا إلا إذا حددت أيضًا. willPauseWhenDucked(true) أو setAcceptsDelayedFocusGain(true) في الطلب.

هناك طريقتان لإعداد المستمع: الطريقة الأولى مع وسيطة المعالج. المعالِج هو سلسلة المحادثات التي يعمل فيها المستمع. إذا كنت عدم تحديد معالج، فإن المعالج المرتبط يتم استخدام Looper.

يوضح المثال التالي كيفية استخدام AudioFocusRequest.Builder لإنشاء AudioFocusRequest وطلب التركيز الصوتي والتخلي عنه:

Kotlin

// initializing variables for audio focus and playback management
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run {
    setAudioAttributes(AudioAttributes.Builder().run {
        setUsage(AudioAttributes.USAGE_GAME)
        setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        build()
    })
    setAcceptsDelayedFocusGain(true)
    setOnAudioFocusChangeListener(afChangeListener, handler)
    build()
}
val focusLock = Any()

var playbackDelayed = false
var playbackNowAuthorized = false

// requesting audio focus and processing the response
val res = audioManager.requestAudioFocus(focusRequest)
synchronized(focusLock) {
    playbackNowAuthorized = when (res) {
        AudioManager.AUDIOFOCUS_REQUEST_FAILED -> false
        AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> {
            playbackNow()
            true
        }
        AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> {
            playbackDelayed = true
            false
        }
        else -> false
    }
}

// implementing OnAudioFocusChangeListener to react to focus changes
override fun onAudioFocusChange(focusChange: Int) {
    when (focusChange) {
        AudioManager.AUDIOFOCUS_GAIN ->
            if (playbackDelayed || resumeOnFocusGain) {
                synchronized(focusLock) {
                    playbackDelayed = false
                    resumeOnFocusGain = false
                }
                playbackNow()
            }
        AudioManager.AUDIOFOCUS_LOSS -> {
            synchronized(focusLock) {
                resumeOnFocusGain = false
                playbackDelayed = false
            }
            pausePlayback()
        }
        AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
            synchronized(focusLock) {
                // only resume if playback is being interrupted
                resumeOnFocusGain = isPlaying()
                playbackDelayed = false
            }
            pausePlayback()
        }
        AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
            // ... pausing or ducking depends on your app
        }
    }
}

Java

// initializing variables for audio focus and playback management
audioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE);
playbackAttributes = new AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_GAME)
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .build();
focusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
        .setAudioAttributes(playbackAttributes)
        .setAcceptsDelayedFocusGain(true)
        .setOnAudioFocusChangeListener(afChangeListener, handler)
        .build();
final Object focusLock = new Object();

boolean playbackDelayed = false;
boolean playbackNowAuthorized = false;

// requesting audio focus and processing the response
int res = audioManager.requestAudioFocus(focusRequest);
synchronized(focusLock) {
    if (res == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
        playbackNowAuthorized = false;
    } else if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
        playbackNowAuthorized = true;
        playbackNow();
    } else if (res == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
        playbackDelayed = true;
        playbackNowAuthorized = false;
    }
}

// implementing OnAudioFocusChangeListener to react to focus changes
@Override
public void onAudioFocusChange(int focusChange) {
    switch (focusChange) {
        case AudioManager.AUDIOFOCUS_GAIN:
            if (playbackDelayed || resumeOnFocusGain) {
                synchronized(focusLock) {
                    playbackDelayed = false;
                    resumeOnFocusGain = false;
                }
                playbackNow();
            }
            break;
        case AudioManager.AUDIOFOCUS_LOSS:
            synchronized(focusLock) {
                resumeOnFocusGain = false;
                playbackDelayed = false;
            }
            pausePlayback();
            break;
        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
            synchronized(focusLock) {
                // only resume if playback is being interrupted
                resumeOnFocusGain = isPlaying();
                playbackDelayed = false;
            }
            pausePlayback();
            break;
        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
            // ... pausing or ducking depends on your app
            break;
        }
    }
}

تجنب التداخل التلقائي

في Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، عندما يطلب تطبيق آخر التركيز مع AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK يمكن للنظام خفض مستوى الصوت واستعادة مستوى الصوت. بدون استدعاء ميزة معاودة الاتصال onAudioFocusChange() الخاصة بالتطبيق.

إنّ التشويش التلقائي يُعدّ سلوكًا مقبولاً في تشغيل الموسيقى والفيديو إلا أنه لا يكون مفيدًا عند تشغيل المحتوى المنطوق، كما هو الحال في تطبيق كتاب مسموع. في هذه الحالة، يجب أن يتوقف التطبيق مؤقتًا بدلاً من ذلك.

إذا أردت أن يتوقف تطبيقك مؤقتًا عندما يُطلب منك خفض مستوى صوته بدلاً من خفض مستوى الصوت، أنشئ OnAudioFocusChangeListener باستخدام طريقة استدعاء onAudioFocusChange() تؤدي إلى تنفيذ سلوك الإيقاف المؤقت/الاستئناف المطلوب. يمكنك الاتصال بالرقم setOnAudioFocusChangeListener() لتسجيل المستمع ثم الاتصال. setWillPauseWhenDucked(true) لإخبار النظام باستخدام معاودة الاتصال بدلاً من تنفيذ تجنب التداخل تلقائيًا.

تأخّر زيادة التركيز

في بعض الأحيان، يتعذر على النظام منح طلب للتركيز الصوتي لأن التركيز "مقفل" باستخدام تطبيق آخر، مثلاً أثناء مكالمة هاتفية. وفي هذه الحالة، تُرجع requestAudioFocus() مبلغ AUDIOFOCUS_REQUEST_FAILED. عندما يحدث هذا، يجب ألا يواصل التطبيق تشغيل الصوت لأنه لم يتم التركيز.

الطريقة، setAcceptsDelayedFocusGain(true)، التي تتيح لتطبيقك معالجة طلب التركيز بشكل غير متزامن. عند ضبط هذه العلامة، يتم تقديم طلب عندما يكون التركيز مُقفَلاً تعرض AUDIOFOCUS_REQUEST_DELAYED. عندما يكون الشرط الذي أدى إلى قفل الصوت لم يعد التركيز موجودًا، كما هو الحال عند انتهاء مكالمة هاتفية، أو عندما يمنح طلب التركيز الذي لا يزال في انتظار المراجعة ويتصل بـ onAudioFocusChange() لإعلام التطبيق.

لمعالجة الزيادة المتأخرة في التركيز، يجب عليك إنشاء OnAudioFocusChangeListener باستخدام طريقة معاودة الاتصال onAudioFocusChange() التي وتنفيذ السلوك المطلوب وتسجيل المستمع من خلال استدعاء setOnAudioFocusChangeListener()

ميزة "تركيز الصوت" في الإصدار 7.1 من نظام Android والإصدارات الأقدم

عند الاتصال requestAudioFocus() فيجب تحديد تلميح للمدة، والذي قد أحد التطبيقات الأخرى التي يتم حاليًا التركيز عليها وتشغيلها:

  • يمكنك طلب التركيز على الصوت الدائم (AUDIOFOCUS_GAIN) عند التخطيط لتشغيل الصوت. في المستقبل القريب (على سبيل المثال، عند تشغيل الموسيقى) وتتوقع المالك السابق لتركيز الصوت لإيقاف التشغيل.
  • طلب التركيز المؤقت (AUDIOFOCUS_GAIN_TRANSIENT) عندما تتوقّع اللعب الصوت لفترة قصيرة فقط وتتوقع أن يتوقّف المستخدم السابق عن العمل مؤقتًا اللعب.
  • طلب التركيز المؤقت من خلال التحايل (AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) للإشارة إلى أنّك تتوقّع تشغيل صوت لفترة قصيرة فقط وأنه من المقبول أن يواصل مالك التركيز السابق اللعب إذا كان "بط" (يخفض) إخراج الصوت. كلا مخرجات الصوت مختلطة مع البث الصوتي ويُعدّ تطبيق Ducking مناسبًا للتطبيقات التي تستخدم البث الصوتي بشكل متقطّع، مثلاً لتوجيهات القيادة الصوتية

تتطلّب الطريقة requestAudioFocus() أيضًا السمة AudioManager.OnAudioFocusChangeListener. يجب أن يكون هذا المستمع تم إنشاؤها في النشاط أو الخدمة نفسها التي تملك جلسة الوسائط. أُنشأها جون هنتر، الذي كان متخصصًا لتنفيذ استدعاء onAudioFocusChange() الذي يتلقّاه تطبيقك عند يكتسب تطبيق آخر التركيز الصوتي أو يتوقف عن التركيز.

يطلب المقتطف التالي التركيز الصوتي الدائم في البث STREAM_MUSIC ويسجِّل OnAudioFocusChangeListener للتعامل معه. التغييرات اللاحقة في التركيز الصوتي. (تتم مناقشة مستمع التغيير في الاستجابة لتغيير التركيز الصوتي).

Kotlin

audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
lateinit var afChangeListener AudioManager.OnAudioFocusChangeListener

...
// Request audio focus for playback
val result: Int = audioManager.requestAudioFocus(
        afChangeListener,
        // Use the music stream.
        AudioManager.STREAM_MUSIC,
        // Request permanent focus.
        AudioManager.AUDIOFOCUS_GAIN
)

if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // Start playback
}

Java

AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
AudioManager.OnAudioFocusChangeListener afChangeListener;

...
// Request audio focus for playback
int result = audioManager.requestAudioFocus(afChangeListener,
                             // Use the music stream.
                             AudioManager.STREAM_MUSIC,
                             // Request permanent focus.
                             AudioManager.AUDIOFOCUS_GAIN);

if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // Start playback
}

عند الانتهاء من التشغيل، اتصل abandonAudioFocus()

Kotlin

audioManager.abandonAudioFocus(afChangeListener)

Java

// Abandon audio focus when playback complete
audioManager.abandonAudioFocus(afChangeListener);

وسيؤدي ذلك إلى إعلام النظام بأنّك لم تعُد بحاجة إلى التركيز، كما يؤدّي إلى إلغاء تسجيل المرتبطة OnAudioFocusChangeListener. إذا طلبت التركيز العابر، سيُرسل هذا إشعارًا إلى التطبيق الذي توقف مؤقتًا أو توقف عن العمل أو أنه قد يستمر في التشغيل أو لاستعادة مستوى الصوت.

الاستجابة لتغيير التركيز الصوتي

عندما يكتسب أحد التطبيقات تركيزًا صوتيًا، يجب أن يكون قادرًا على تحريره عندما يكون هناك تطبيق آخر يطلب التركيز على الصوت لنفسه. وعند حدوث ذلك، فإن تطبيقك تلقي مكالمة مع onAudioFocusChange() في AudioFocusChangeListener الذي حددته عند تشغيل التطبيق المسمى requestAudioFocus().

تشير مَعلمة focusChange التي يتم تمريرها إلى onAudioFocusChange() إلى النوع. للتغيير الذي يحدث. يتجاوب إلى تلميح المدة الذي يستخدمه التطبيق الذي يلفت الانتباه. يجب أن الاستجابة بشكل مناسب.

فقد التركيز بشكل عابر
إذا كان تغيير التركيز عابرًا (AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK أو AUDIOFOCUS_LOSS_TRANSIENT)، سيتراجع تطبيقك (إذا كنت لا تعتمد عند التحايل التلقائي) أو إيقاف التشغيل مؤقتًا تحافظ على نفس الحالة.

يجب أن تستمر في مراقبة التغييرات أثناء فقدان التركيز مؤقتًا في الصوت. في وضع تركيز الصوت والاستعداد لاستئناف التشغيل العادي عند استعادة التركيز. عندما يتوقف تطبيق الحظر عن التركيز، ستتلقّى معاودة الاتصال. (AUDIOFOCUS_GAIN). عند هذه النقطة، يمكنك استعادة مستوى الصوت إلى المستوى العادي. أو إعادة بدء التشغيل

فقدان التركيز نهائيًا
إذا كان فقدان التركيز الصوتي نهائيًا (AUDIOFOCUS_LOSS)، يعني هذا أنّ تطبيقًا آخر يَتِمُّ الْآنْ تَشْغِيلُ الصَّوْتْ. من المفترض أن يتم إيقاف تشغيل تطبيقك مؤقتًا بشكل فوري، لأنه لن يتم تشغيله أبدًا. تلقّي معاودة الاتصال من "AUDIOFOCUS_GAIN" ولإعادة تشغيل التشغيل، على المستخدم اتخاذ إجراء صريح، مثل الضغط على عنصر تحكم النقل في Play في إشعار أو واجهة مستخدم التطبيق.

يوضح مقتطف الرمز التالي كيفية تنفيذ "OnAudioFocusChangeListener" ومعاودة الاتصال "onAudioFocusChange()" الخاصة به. لاحظ استخدام Handler لتأخير إيقاف معاودة الاتصال عند فقدان الصوت نهائيًا التركيز.

Kotlin

private val handler = Handler()
private val afChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange ->
    when (focusChange) {
        AudioManager.AUDIOFOCUS_LOSS -> {
            // Permanent loss of audio focus
            // Pause playback immediately
            mediaController.transportControls.pause()
            // Wait 30 seconds before stopping playback
            handler.postDelayed(delayedStopRunnable, TimeUnit.SECONDS.toMillis(30))
        }
        AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
            // Pause playback
        }
        AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
            // Lower the volume, keep playing
        }
        AudioManager.AUDIOFOCUS_GAIN -> {
            // Your app has been granted audio focus again
            // Raise volume to normal, restart playback if necessary
        }
    }
}

Java

private Handler handler = new Handler();
AudioManager.OnAudioFocusChangeListener afChangeListener =
  new AudioManager.OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
      if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
        // Permanent loss of audio focus
        // Pause playback immediately
        mediaController.getTransportControls().pause();
        // Wait 30 seconds before stopping playback
        handler.postDelayed(delayedStopRunnable,
          TimeUnit.SECONDS.toMillis(30));
      }
      else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
        // Pause playback
      } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
        // Lower the volume, keep playing
      } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
        // Your app has been granted audio focus again
        // Raise volume to normal, restart playback if necessary
      }
    }
  };

يستخدم المعالج علامة Runnable على النحو التالي:

Kotlin

private var delayedStopRunnable = Runnable {
    mediaController.transportControls.stop()
}

Java

private Runnable delayedStopRunnable = new Runnable() {
    @Override
    public void run() {
        getMediaController().getTransportControls().stop();
    }
};

وللتأكد من عدم بدء فترة التوقف المتأخر في حال أعاد المستخدم تشغيل التشغيل، اتصل mHandler.removeCallbacks(mDelayedStopRunnable) استجابةً لأي ولاية التغييرات. على سبيل المثال، يمكنك طلب removeCallbacks() من خلال الرقم onPlay() الخاص بمعاودة الاتصال. onSkipToNext()، إلخ. كما يجب عليك أيضًا استدعاء هذه الطريقة في حساب يمكنك معاودة الاتصال onDestroy() عند إخلاء الموارد التي تستخدمها خدمتك.