שתי אפליקציות Android או יותר יכולות להפעיל אודיו באותו מקור פלט בו-זמנית, והמערכת מערבבת את כולן. זהו יכול להיות מרשים מבחינה טכנית, אבל יכול להיות מאוד מתסכל למשתמש. כדי למנוע מצב שבו כל אפליקציית מוזיקה תופעל בו-זמנית, ב-Android הוספנו את התכונה מיקוד אודיו. רק אפליקציה אחת יכולה להתמקד באודיו בכל פעם.
כשהאפליקציה צריכה להפיק אודיו, היא צריכה לבקש הרשאת שליטה באודיו. כשהיא בחזית, היא יכולה להשמיע צלילים. עם זאת, יכול להיות שאי אפשר יהיה לשמור על המיקוד באודיו עד לסיום ההפעלה. אפליקציה אחרת יכולה לבקש להתמקד בה, וכך לבטל את ההחזקה שלכם על התמקדות האודיו. במקרה כזה, האפליקציה צריכה להשהות את ההפעלה או להנמיך את עוצמת הקול כדי לאפשר למשתמשים לשמוע בקלות רבה יותר את מקור האודיו החדש.
לפני Android 12 (רמת API 31), המערכת לא מנהלת את המיקוד האודיו. לכן, למרות שמפתחי אפליקציות מומלצים לפעול בהתאם להנחיות בנושא התמקדות באודיו, אם אפליקציה ממשיכה להשמיע קול רם גם אחרי שהיא מפסיקה להיות מוגדרת כממוקדת באודיו במכשיר עם Android 11 (רמת API 30) או גרסה ישנה יותר, המערכת לא יכולה למנוע זאת. עם זאת, התנהגות האפליקציה הזו מובילה לחוויית משתמש גרועה, ולעיתים קרובות המשתמשים מסירים את האפליקציה שמתנהגת בצורה לא תקינה.
אפליקציית אודיו שתוכננה היטב צריכה לנהל את מיקוד האודיו בהתאם להנחיות הכלליות הבאות:
מתקשרים למספר
requestAudioFocus()
מיד לפני שמתחילים לנגן ומאמתים שהשיחה מחזירה את הערךAUDIOFOCUS_REQUEST_GRANTED
. מבצעים את השיחה אלrequestAudioFocus()
בקריאה החוזרתonPlay()
של סשן המדיה.כשאפליקציה אחרת מקבלת את המיקוד של האודיו, אפשר להפסיק או להשהות את ההפעלה או להקטין את עוצמת הקול.
כשההפעלה נעצרת (לדוגמה, כשאין יותר תוכן באפליקציה שאפשר להפעיל), צריך לבטל את המיקוד באודיו. האפליקציה לא צריכה לוותר על התמקדות באודיו אם המשתמש משהה את ההפעלה, אבל יכול להיות שהוא ימשיך את ההפעלה מאוחר יותר.
משתמשים ב-
AudioAttributes
כדי לתאר את סוג האודיו שהאפליקציה מפעילה. לדוגמה, באפליקציות שמשמיעות דיבור, צריך לציין את הערךCONTENT_TYPE_SPEECH
.
המערכת מטפלת במיקוד האודיו באופן שונה בהתאם לגרסה של Android שפועלת במכשיר:
- Android 12 (רמת API 31) ואילך
- המערכת מנהלת את המיקוד באודיו. המערכת מאלצת את הפעלת האודיו מאפליקציה מסוימת להתפוגג כשאפליקציה אחרת מבקשת להתמקד באודיו. בנוסף, כשמקבלים שיחה נכנסת, המערכת משתיקה את הפעלת האודיו.
- Android 8.0 (רמת API 26) עד Android 11 (רמת API 30)
- המערכת לא מנהלת את התמקדות האודיו, אבל היא כוללת כמה שינויים שהושקו החל מגרסה 8.0 של Android (רמת API 26).
- Android 7.1 (רמת API 25) ומטה
- המערכת לא מנהלת את התמקדות האודיו, והאפליקציות מנהלות את התמקדות האודיו באמצעות הלחצנים
requestAudioFocus()
ו-abandonAudioFocus()
.
מיקוד אודיו ב-Android מגרסה 12 ואילך
אפליקציית מדיה או משחק שמשתמשת בהתמקדות באודיו לא אמורה להפעיל אודיו אחרי שהיא מאבדת את ההתמקדות. ב-Android 12 (רמת API 31) ואילך, המערכת אוכפת את ההתנהגות הזו. כשאפליקציה מבקשת להתמקד באודיו בזמן שאפליקציה אחרת ממוקדת ומשמיעה אודיו, המערכת מאלצת את האפליקציה שמשמיעה אודיו לדעוך. הוספת ההעלמה מאפשרת מעבר חלק יותר בין אפליקציות.
ההתנהגות הזו מתרחשת כשמתקיימים התנאים הבאים:
האפליקציה הראשונה שפועלת כרגע עומדת בכל הקריטריונים הבאים:
- באפליקציה יש את מאפיין השימוש
AudioAttributes.USAGE_MEDIA
או את המאפייןAudioAttributes.USAGE_GAME
. - האפליקציה ביקשה להתמקד באודיו עם
AudioManager.AUDIOFOCUS_GAIN
. - האפליקציה לא מפעילה אודיו מסוג התוכן
AudioAttributes.CONTENT_TYPE_SPEECH
.
- באפליקציה יש את מאפיין השימוש
אפליקציה שנייה מבקשת הרשאת אודיו באמצעות
AudioManager.AUDIOFOCUS_GAIN
.
כשהתנאים האלה מתקיימים, מערכת האודיו מפחיתה בהדרגה את עוצמת הקול באפליקציה הראשונה. בסיום ההפחתה, המערכת מעדכנת את האפליקציה הראשונה על אובדן המיקוד. נגני האפליקציה יישארו מושתקים עד שהאפליקציה תבקש שוב את הרשאת האודיו.
התנהגויות קיימות של מיקוד אודיו
חשוב גם לדעת על המקרים הבאים שבהם מתבצע מעבר של מוקד האודיו.
הנמכה אוטומטית של עוצמת הקול
התכונה 'הנמכה אוטומטית של עוצמת השמע' (הפחתה זמנית של עוצמת השמע באפליקציה אחת כדי שאפשר יהיה לשמוע אפליקציה אחרת בבירור) הושקה ב-Android 8.0 (רמת API 26).
כשהמערכת מטמיעה את ההשתקה, אין צורך להטמיע אותה באפליקציה.
השקטה אוטומטית מתרחשת גם כשהתמקדות עוברת מאפליקציה שפועלת להפעלת אודיו להתראה קולית. תחילת ההפעלה של ההתראה מסונכרנת עם סיום הירידה בעצמת הקול.
ההשתקה האוטומטית מתרחשת כשהתנאים הבאים מתקיימים:
האפליקציה הראשונה שמופעלת כרגע עומדת בכל הקריטריונים הבאים:
- האפליקציה ביקשה להתמקד באודיו עם כל סוג של שיפור התמקדות.
- האפליקציה לא מפעילה אודיו מסוג התוכן
AudioAttributes.CONTENT_TYPE_SPEECH
. - האפליקציה לא הגדרה את
AudioFocusRequest.Builder.setWillPauseWhenDucked(true)
.
אפליקציה שנייה מבקשת הרשאת אודיו באמצעות
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
.
כשהתנאים האלה מתקיימים, מערכת האודיו משתיקה את כל הנגנים הפעילים באפליקציה הראשונה בזמן שהאפליקציה השנייה נמצאת בחזית. כשהאפליקציה השנייה מפסיקה להיות במוקד, התמונות והסרטונים חוזרים למצב רגיל. האפליקציה הראשונה לא מקבלת התראה כשהיא מאבדת את המיקוד, ולכן היא לא צריכה לעשות כלום.
חשוב לזכור שהשתקה אוטומטית לא מתבצעת כשהמשתמש מקשיב לתוכן דיבור, כי יכול להיות שהוא יחמיץ חלק מהתוכנית. לדוגמה, הנחיות קוליות למסלולי נסיעה לא מושתקות.
השתקת ההפעלה הנוכחית של האודיו בשיחות טלפון נכנסות
חלק מהאפליקציות לא פועלות כראוי וממשיכות להפעיל אודיו במהלך שיחות טלפון. המצב הזה מאלץ את המשתמש למצוא את האפליקציה הבעייתית ולהשתיק אותה או לצאת ממנה כדי לשמוע את השיחה. כדי למנוע זאת, המערכת יכולה להשתיק את האודיו מאפליקציות אחרות בזמן שיחה נכנסת. המערכת מפעילה את התכונה הזו כשמתקבלת שיחה נכנסת בטלפון ואפליקציה עומדת בתנאים הבאים:
- לאפליקציה יש את מאפיין השימוש
AudioAttributes.USAGE_MEDIA
אוAudioAttributes.USAGE_GAME
. - האפליקציה ביקשה להתמקד באודיו (כל התמקדות) והיא מפעילה אודיו.
אם אפליקציה ממשיכה לפעול במהלך השיחה, ההפעלה שלה תושתק עד לסיום השיחה. עם זאת, אם אפליקציה מתחילה לפעול במהלך השיחה, הנגן לא מושתק מתוך הנחה שהמשתמש הפעיל את ההפעלה בכוונה.
התמקדות באודיו ב-Android מגרסה 8.0 ועד Android 11
החל מגרסה Android 8.0 (רמת API 26), כשקוראים ל-requestAudioFocus()
צריך לספק פרמטר AudioFocusRequest
. השדה AudioFocusRequest
מכיל מידע על ההקשר והיכולות של השמע באפליקציה. המערכת משתמשת במידע הזה כדי לנהל באופן אוטומטי את העלייה והירידה ברמת המיקוד של השמע. כדי לשחרר את הרשאת האודיו, צריך לבצע קריאה ל-method abandonAudioFocusRequest()
, שגם הוא מקבל את AudioFocusRequest
כארגומנטים. צריך להשתמש באותו מופע של AudioFocusRequest
גם כשמבקשים להתמקד וגם כשמבטלים את ההתמקדות.
כדי ליצור AudioFocusRequest
, משתמשים ב-AudioFocusRequest.Builder
. מכיוון שבבקשת התמקדות תמיד צריך לציין את סוג הבקשה, הסוג נכלל ב-constructor של ה-builder. משתמשים בשיטות של ה-builder כדי להגדיר את שאר השדות של הבקשה.
השדה FocusGain
הוא חובה, כל שאר השדות הם אופציונליים.
שיטה | הערות |
---|---|
setFocusGain()
|
השדה הזה נדרש בכל בקשה. הוא מקבל את אותם ערכים כמו durationHint ששימש בקריאה ל-requestAudioFocus() לפני Android 8.0: AUDIOFOCUS_GAIN , AUDIOFOCUS_GAIN_TRANSIENT , AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK או AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE .
|
setAudioAttributes()
|
AudioAttributes מתאר את התרחיש לדוגמה של האפליקציה. המערכת בודקת את התרחישים האלה כשאפליקציה מקבלת או מאבדת את המיקוד של האודיו. המאפיינים מחליפים את הרעיון של סוג הסטרימינג. ב-Android מגרסה 8.0 (רמת API 26) ואילך, סוגי הסטרימינג של כל פעולה מלבד אמצעי הבקרה של עוצמת הקול הוצאו משימוש. צריך להשתמש באותם מאפיינים בבקשת המיקוד שבה אתם משתמשים בנגן האודיו (כפי שמוצג בדוגמה שמופיעה אחרי הטבלה הזו).
קודם צריך להשתמש ב-
אם לא מציינים ערך, |
setWillPauseWhenDucked()
|
כשאפליקציה אחרת מבקשת להתמקד באמצעות AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK , בדרך כלל לא מתקבל קריאה חוזרת (callback) של onAudioFocusChange() באפליקציה שבה יש מיקוד, כי המערכת יכולה לבצע את ההסתרה בעצמה. אם אתם צריכים להשהות את ההפעלה במקום להנמיך את עוצמת הקול, צריך להפעיל את הפונקציה setWillPauseWhenDucked(true) וליצור ולהגדיר אירוע OnAudioFocusChangeListener , כפי שמתואר בקטע הנמכת עוצמת קול אוטומטית.
|
setAcceptsDelayedFocusGain()
|
בקשה להרשאת אודיו עשויה להיכשל אם אפליקציה אחרת נעולה עליה. השיטה הזו מאפשרת קבלת הרשאת אודיו באיחור: היכולת לקבל את ההרשאה באופן אסינכרוני כשהיא זמינה.
חשוב לזכור שהפעלת הבקשה להעברת המיקוד באיחור פועלת רק אם מציינים גם את הערך |
setOnAudioFocusChangeListener()
|
צריך לציין OnAudioFocusChangeListener רק אם מציינים גם את willPauseWhenDucked(true) או את setAcceptsDelayedFocusGain(true) בבקשה.
יש שתי שיטות להגדרת המאזין: אחת עם ארגומנטים של טיפול והשנייה בלי. הטיפול הוא השרשור שבו פועל המאזין. אם לא מציינים טיפול, המערכת משתמשת בטיפול שמשויך ל- |
בדוגמה הבאה מוסבר איך להשתמש ב-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 (רמת API 26), כשאפליקציה אחרת מבקשת להתמקד באמצעות AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
, המערכת יכולה להפחית את עוצמת הקול ולשחזר אותה בלי להפעיל את פונקציית ה-callback onAudioFocusChange()
של האפליקציה.
אמנם השהיה אוטומטית היא התנהגות מקובלת באפליקציות להפעלת מוזיקה וסרטונים, אבל היא לא שימושית כשמפעילים תוכן דיבור, למשל באפליקציית אודיו-ספרים. במקרה כזה, האפליקציה צריכה להשהות את התוכן במקום זאת.
אם אתם רוצים שהאפליקציה תיפסק כשמתבקשים להשתיק אותה במקום להפחית את עוצמת הקול, צריך ליצור OnAudioFocusChangeListener
עם שיטה של onAudioFocusChange()
חזרה (callback) שמטמיעה את ההתנהגות הרצויה של השהיה/המשך.
קוראים ל-setOnAudioFocusChangeListener()
כדי לרשום את המאזין, וקוראים ל-setWillPauseWhenDucked(true)
כדי להורות למערכת להשתמש בקריאה החוזרת שלכם במקום לבצע הנמכה אוטומטית של עוצמת הקול.
התחזקות מטושטשת
לפעמים המערכת לא יכולה לאשר בקשה להתמקד באודיו כי האפליקציה אחרת 'נעל' את המיקוד, למשל במהלך שיחת טלפון. במקרה הזה, הפונקציה requestAudioFocus()
מחזירה את הערך AUDIOFOCUS_REQUEST_FAILED
. במקרה כזה, האפליקציה לא אמורה להמשיך בהפעלת האודיו כי היא לא קיבלה את המיקוד.
השיטה setAcceptsDelayedFocusGain(true)
שמאפשרת לאפליקציה לטפל בבקשה להעברת המיקוד באופן אסינכרוני. כשהדגל הזה מוגדר, בקשה שנשלחת כשהמיקוד נעול מחזירה את הערך AUDIOFOCUS_REQUEST_DELAYED
. כשהתנאי שגרם לנעילת המיקוד של האודיו לא קיים יותר, למשל כששיחת הטלפון מסתיימת, המערכת מעניקה את בקשת המיקוד בהמתנה ומפעילה את onAudioFocusChange()
כדי להודיע לאפליקציה.
כדי לטפל בהשגת המיקוד המאוחר, צריך ליצור OnAudioFocusChangeListener
עם method onAudioFocusChange()
של קריאה חוזרת שמטמיע את ההתנהגות הרצויה, ולרשום את המאזין באמצעות קריאה ל-setOnAudioFocusChangeListener()
.
מיקוד אודיו ב-Android מגרסה 7.1 ומטה
כשקוראים ל-requestAudioFocus()
, צריך לציין רמז למשך הזמן. אפליקציה אחרת שמתמקדת כרגע ומפעילה תוכן עשויה לפעול לפי הרמז:
- כדאי לבקש שליטה קבועה באודיו (
AUDIOFOCUS_GAIN
) אם אתם מתכננים להפעיל אודיו בעתיד הקרוב (לדוגמה, כשאתם מנגנים מוזיקה) ואתם מצפים שהאפליקציה הקודמת שהחזיקה בשליטה באודיו תפסיק להפעיל אודיו. - כדאי לבקש מיקוד זמני (
AUDIOFOCUS_GAIN_TRANSIENT
) כשאתם מתכוונים להפעיל אודיו למשך זמן קצר בלבד, ומצפים שהבעלים הקודם יפסיק את ההפעלה. - אפשר לבקש להתמקד באופן זמני עם דעיכה (
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
) כדי לציין שאתם מתכוונים להפעיל אודיו רק לזמן קצר, ושזה בסדר אם הבעלים הקודם של המיקוד ימשיך להפעיל את התוכן שלו אם הוא 'ידועך' (ירידה) את פלט האודיו שלו. שני פלטי האודיו מעורבבים בשידור האודיו. הדחקה מתאימה במיוחד לאפליקציות שמשתמשות בסטרימינג של אודיו לסירוגין, למשל להנחיות קוליות לנהיגה.
השיטה requestAudioFocus()
דורשת גם AudioManager.OnAudioFocusChangeListener
. צריך ליצור את המאזין הזה באותה פעילות או באותו שירות שבבעלותם סשן המדיה. הוא מטמיע את פונקציית ה-callback 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);
הפעולה הזו תודיע למערכת שאתם לא זקוקים יותר ל-focus, ותבטל את הרישום של OnAudioFocusChangeListener
המשויך. אם תבקשו להעביר את המיקוד באופן זמני, האפליקציה שתושהה או שתוצג בהשתקה תקבל הודעה על כך שאפשר להמשיך את ההפעלה או לשחזר את עוצמת הקול שלה.
תגובה לשינוי המיקוד של האודיו
כשאפליקציה מקבלת את המיקוד באודיו, היא צריכה להיות מסוגלת לשחרר אותו כשאפליקציה אחרת מבקשת לקבל את המיקוד באודיו. במקרה כזה, האפליקציה מקבלת קריאה ל-method onAudioFocusChange()
ב-AudioFocusChangeListener
שציינתם כשהאפליקציה התקשרה ל-requestAudioFocus()
.
הפרמטר focusChange
שמוענק ל-onAudioFocusChange()
מציין את סוג השינוי שמתרחש. הוא תואם לאינדיקטור משך הזמן שבו משתמשת האפליקציה שמקבלת את המיקוד. האפליקציה אמורה להגיב בצורה הולמת.
- אובדן מיקוד זמני
-
אם שינוי המיקוד הוא זמני (
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
אוAUDIOFOCUS_LOSS_TRANSIENT
), האפליקציה צריכה להשתיק את האודיו (אם אתם לא מסתמכים על השתקה אוטומטית) או להשהות את ההפעלה, אבל לשמור על אותו מצב בכל שאר הזמן.במהלך אובדן זמני של הרשאת האודיו, כדאי להמשיך לעקוב אחרי השינויים בהרשאת האודיו ולהתכונן להמשיך את ההפעלה הרגילה כשהיא תוחזר. כשהאפליקציה החוסמת מפסיקה להתמקד, תקבלו קריאה חוזרת (
AUDIOFOCUS_GAIN
). בשלב הזה תוכלו להחזיר את עוצמת הקול לרמה הרגילה או להפעיל מחדש את ההפעלה. - אובדן פוקוס קבוע
-
אם אובדן המיקוד באודיו הוא קבוע (
AUDIOFOCUS_LOSS
), אפליקציה אחרת מפעילה אודיו. האפליקציה צריכה להשהות את ההפעלה באופן מיידי, כי היא לעולם לא תקבל קריאה חוזרת מ-AUDIOFOCUS_GAIN
. כדי להפעיל מחדש את ההפעלה, המשתמש צריך לבצע פעולה מפורשת, כמו לחיצה על לחצן ההפעלה בהתראה או בממשק המשתמש של האפליקציה.
קטע הקוד הבא מראה איך מטמיעים את OnAudioFocusChangeListener
ואת הפונקציה החוזרת (callback) שלו, 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()
וכו' של פונקציית ה-Callback. צריך גם לקרוא ל-method הזה ב-Callback onDestroy()
של השירות כשמנקים את המשאבים שבהם השירות משתמש.