1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view.accessibility; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.RequiresPermission; 23 import android.annotation.SystemApi; 24 import android.annotation.SystemService; 25 import android.compat.annotation.UnsupportedAppUsage; 26 import android.content.ContentResolver; 27 import android.content.Context; 28 import android.content.res.Resources; 29 import android.database.ContentObserver; 30 import android.graphics.Color; 31 import android.graphics.Typeface; 32 import android.net.Uri; 33 import android.os.Handler; 34 import android.provider.Settings.Secure; 35 import android.text.TextUtils; 36 37 import com.android.internal.R; 38 39 import java.util.ArrayList; 40 import java.util.Locale; 41 42 /** 43 * Contains methods for accessing and monitoring preferred video captioning state and visual 44 * properties. 45 */ 46 @SystemService(Context.CAPTIONING_SERVICE) 47 public class CaptioningManager { 48 /** Default captioning enabled value. */ 49 private static final int DEFAULT_ENABLED = 0; 50 private static final boolean SYSTEM_AUDIO_CAPTIONING_DEFAULT_ENABLED = false; 51 52 /** Default style preset as an index into {@link CaptionStyle#PRESETS}. */ 53 private static final int DEFAULT_PRESET = 0; 54 55 /** Default scaling value for caption fonts. */ 56 private static final float DEFAULT_FONT_SCALE = 1; 57 58 private final ArrayList<CaptioningChangeListener> mListeners = new ArrayList<>(); 59 private final ContentResolver mContentResolver; 60 private final ContentObserver mContentObserver; 61 private final Resources mResources; 62 private final Context mContext; 63 private final AccessibilityManager mAccessibilityManager; 64 65 /** 66 * Creates a new captioning manager for the specified context. 67 * 68 * @hide 69 */ CaptioningManager(Context context)70 public CaptioningManager(Context context) { 71 mContext = context; 72 mContentResolver = context.getContentResolver(); 73 mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); 74 75 final Handler handler = new Handler(context.getMainLooper()); 76 mContentObserver = new MyContentObserver(handler); 77 mResources = context.getResources(); 78 } 79 80 /** 81 * @return the user's preferred captioning enabled state 82 */ isEnabled()83 public final boolean isEnabled() { 84 return Secure.getInt( 85 mContentResolver, Secure.ACCESSIBILITY_CAPTIONING_ENABLED, DEFAULT_ENABLED) == 1; 86 } 87 88 /** 89 * @return the raw locale string for the user's preferred captioning 90 * language 91 * @hide 92 */ 93 @Nullable getRawLocale()94 public final String getRawLocale() { 95 return Secure.getString(mContentResolver, Secure.ACCESSIBILITY_CAPTIONING_LOCALE); 96 } 97 98 /** 99 * @return the locale for the user's preferred captioning language, or null 100 * if not specified 101 */ 102 @Nullable getLocale()103 public final Locale getLocale() { 104 final String rawLocale = getRawLocale(); 105 if (!TextUtils.isEmpty(rawLocale)) { 106 final String[] splitLocale = rawLocale.split("_"); 107 switch (splitLocale.length) { 108 case 3: 109 return new Locale(splitLocale[0], splitLocale[1], splitLocale[2]); 110 case 2: 111 return new Locale(splitLocale[0], splitLocale[1]); 112 case 1: 113 return new Locale(splitLocale[0]); 114 } 115 } 116 117 return null; 118 } 119 120 /** 121 * @return the user's preferred font scaling factor for video captions, or 1 if not 122 * specified 123 */ getFontScale()124 public final float getFontScale() { 125 return Secure.getFloat( 126 mContentResolver, Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE, DEFAULT_FONT_SCALE); 127 } 128 129 /** 130 * @return the raw preset number, or the first preset if not specified 131 * @hide 132 */ getRawUserStyle()133 public int getRawUserStyle() { 134 return Secure.getInt( 135 mContentResolver, Secure.ACCESSIBILITY_CAPTIONING_PRESET, DEFAULT_PRESET); 136 } 137 138 /** 139 * @return the user's preferred visual properties for captions as a 140 * {@link CaptionStyle}, or the default style if not specified 141 */ 142 @NonNull getUserStyle()143 public CaptionStyle getUserStyle() { 144 final int preset = getRawUserStyle(); 145 if (preset == CaptionStyle.PRESET_CUSTOM) { 146 return CaptionStyle.getCustomStyle(mContentResolver); 147 } 148 149 return CaptionStyle.PRESETS[preset]; 150 } 151 152 /** 153 * @return the system audio caption enabled state. 154 */ isSystemAudioCaptioningEnabled()155 public final boolean isSystemAudioCaptioningEnabled() { 156 return Secure.getIntForUser(mContentResolver, Secure.ODI_CAPTIONS_ENABLED, 157 SYSTEM_AUDIO_CAPTIONING_DEFAULT_ENABLED ? 1 : 0, mContext.getUserId()) == 1; 158 } 159 160 /** 161 * Sets the system audio caption enabled state. 162 * 163 * @param isEnabled The system audio captioning enabled state. 164 * 165 * @throws SecurityException if the caller does not have permission 166 * {@link Manifest.permission#SET_SYSTEM_AUDIO_CAPTION} 167 * 168 * @hide 169 */ 170 @SystemApi 171 @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) setSystemAudioCaptioningEnabled(boolean isEnabled)172 public final void setSystemAudioCaptioningEnabled(boolean isEnabled) { 173 if (mAccessibilityManager != null) { 174 mAccessibilityManager.setSystemAudioCaptioningEnabled(isEnabled, 175 mContext.getUserId()); 176 } 177 } 178 179 /** 180 * @return the system audio caption UI enabled state. 181 */ isSystemAudioCaptioningUiEnabled()182 public final boolean isSystemAudioCaptioningUiEnabled() { 183 return mAccessibilityManager != null 184 && mAccessibilityManager.isSystemAudioCaptioningUiEnabled(mContext.getUserId()); 185 } 186 187 /** 188 * Sets the system audio caption UI enabled state. 189 * 190 * @param isEnabled The system audio captioning UI enabled state. 191 * 192 * @throws SecurityException if the caller does not have permission 193 * {@link Manifest.permission#SET_SYSTEM_AUDIO_CAPTION} 194 * 195 * @hide 196 */ 197 @SystemApi 198 @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) setSystemAudioCaptioningUiEnabled(boolean isEnabled)199 public final void setSystemAudioCaptioningUiEnabled(boolean isEnabled) { 200 if (mAccessibilityManager != null) { 201 mAccessibilityManager.setSystemAudioCaptioningUiEnabled(isEnabled, 202 mContext.getUserId()); 203 } 204 } 205 206 /** 207 * Adds a listener for changes in the user's preferred captioning enabled 208 * state and visual properties. 209 * 210 * @param listener the listener to add 211 */ addCaptioningChangeListener(@onNull CaptioningChangeListener listener)212 public void addCaptioningChangeListener(@NonNull CaptioningChangeListener listener) { 213 synchronized (mListeners) { 214 if (mListeners.isEmpty()) { 215 registerObserver(Secure.ACCESSIBILITY_CAPTIONING_ENABLED); 216 registerObserver(Secure.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR); 217 registerObserver(Secure.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR); 218 registerObserver(Secure.ACCESSIBILITY_CAPTIONING_WINDOW_COLOR); 219 registerObserver(Secure.ACCESSIBILITY_CAPTIONING_EDGE_TYPE); 220 registerObserver(Secure.ACCESSIBILITY_CAPTIONING_EDGE_COLOR); 221 registerObserver(Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE); 222 registerObserver(Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE); 223 registerObserver(Secure.ACCESSIBILITY_CAPTIONING_LOCALE); 224 registerObserver(Secure.ACCESSIBILITY_CAPTIONING_PRESET); 225 registerObserver(Secure.ODI_CAPTIONS_ENABLED); 226 registerObserver(Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED); 227 } 228 229 mListeners.add(listener); 230 } 231 } 232 registerObserver(String key)233 private void registerObserver(String key) { 234 mContentResolver.registerContentObserver(Secure.getUriFor(key), false, mContentObserver); 235 } 236 237 /** 238 * Removes a listener previously added using 239 * {@link #addCaptioningChangeListener}. 240 * 241 * @param listener the listener to remove 242 */ removeCaptioningChangeListener(@onNull CaptioningChangeListener listener)243 public void removeCaptioningChangeListener(@NonNull CaptioningChangeListener listener) { 244 synchronized (mListeners) { 245 mListeners.remove(listener); 246 247 if (mListeners.isEmpty()) { 248 mContentResolver.unregisterContentObserver(mContentObserver); 249 } 250 } 251 } 252 253 /** 254 * Returns true if system wide call captioning is enabled for this device. 255 */ isCallCaptioningEnabled()256 public boolean isCallCaptioningEnabled() { 257 try { 258 return mResources.getBoolean( 259 R.bool.config_systemCaptionsServiceCallsEnabled); 260 } catch (Resources.NotFoundException e) { 261 // The resource may not be defined, return false in that case 262 return false; 263 } 264 } 265 notifyEnabledChanged()266 private void notifyEnabledChanged() { 267 final boolean enabled = isEnabled(); 268 synchronized (mListeners) { 269 for (CaptioningChangeListener listener : mListeners) { 270 listener.onEnabledChanged(enabled); 271 } 272 } 273 } 274 notifyUserStyleChanged()275 private void notifyUserStyleChanged() { 276 final CaptionStyle userStyle = getUserStyle(); 277 synchronized (mListeners) { 278 for (CaptioningChangeListener listener : mListeners) { 279 listener.onUserStyleChanged(userStyle); 280 } 281 } 282 } 283 notifyLocaleChanged()284 private void notifyLocaleChanged() { 285 final Locale locale = getLocale(); 286 synchronized (mListeners) { 287 for (CaptioningChangeListener listener : mListeners) { 288 listener.onLocaleChanged(locale); 289 } 290 } 291 } 292 notifyFontScaleChanged()293 private void notifyFontScaleChanged() { 294 final float fontScale = getFontScale(); 295 synchronized (mListeners) { 296 for (CaptioningChangeListener listener : mListeners) { 297 listener.onFontScaleChanged(fontScale); 298 } 299 } 300 } 301 notifySystemAudioCaptionChanged()302 private void notifySystemAudioCaptionChanged() { 303 final boolean enabled = isSystemAudioCaptioningEnabled(); 304 synchronized (mListeners) { 305 for (CaptioningChangeListener listener : mListeners) { 306 listener.onSystemAudioCaptioningChanged(enabled); 307 } 308 } 309 } 310 notifySystemAudioCaptionUiChanged()311 private void notifySystemAudioCaptionUiChanged() { 312 final boolean enabled = isSystemAudioCaptioningUiEnabled(); 313 synchronized (mListeners) { 314 for (CaptioningChangeListener listener : mListeners) { 315 listener.onSystemAudioCaptioningUiChanged(enabled); 316 } 317 } 318 } 319 320 private class MyContentObserver extends ContentObserver { 321 private final Handler mHandler; 322 MyContentObserver(Handler handler)323 public MyContentObserver(Handler handler) { 324 super(handler); 325 326 mHandler = handler; 327 } 328 329 @Override onChange(boolean selfChange, Uri uri)330 public void onChange(boolean selfChange, Uri uri) { 331 final String uriPath = uri.getPath(); 332 final String name = uriPath.substring(uriPath.lastIndexOf('/') + 1); 333 if (Secure.ACCESSIBILITY_CAPTIONING_ENABLED.equals(name)) { 334 notifyEnabledChanged(); 335 } else if (Secure.ACCESSIBILITY_CAPTIONING_LOCALE.equals(name)) { 336 notifyLocaleChanged(); 337 } else if (Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE.equals(name)) { 338 notifyFontScaleChanged(); 339 } else if (Secure.ODI_CAPTIONS_ENABLED.equals(name)) { 340 notifySystemAudioCaptionChanged(); 341 } else if (Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED.equals(name)) { 342 notifySystemAudioCaptionUiChanged(); 343 } else { 344 // We only need a single callback when multiple style properties 345 // change in rapid succession. 346 mHandler.removeCallbacks(mStyleChangedRunnable); 347 mHandler.post(mStyleChangedRunnable); 348 } 349 } 350 }; 351 352 /** 353 * Runnable posted when user style properties change. This is used to 354 * prevent unnecessary change notifications when multiple properties change 355 * in rapid succession. 356 */ 357 private final Runnable mStyleChangedRunnable = new Runnable() { 358 @Override 359 public void run() { 360 notifyUserStyleChanged(); 361 } 362 }; 363 364 /** 365 * Specifies visual properties for video captions, including foreground and 366 * background colors, edge properties, and typeface. 367 */ 368 public static final class CaptionStyle { 369 /** 370 * Packed value for a color of 'none' and a cached opacity of 100%. 371 * 372 * @hide 373 */ 374 private static final int COLOR_NONE_OPAQUE = 0x000000FF; 375 376 /** 377 * Packed value for a color of 'default' and opacity of 100%. 378 * 379 * @hide 380 */ 381 public static final int COLOR_UNSPECIFIED = 0x00FFFFFF; 382 383 private static final CaptionStyle WHITE_ON_BLACK; 384 private static final CaptionStyle BLACK_ON_WHITE; 385 private static final CaptionStyle YELLOW_ON_BLACK; 386 private static final CaptionStyle YELLOW_ON_BLUE; 387 private static final CaptionStyle DEFAULT_CUSTOM; 388 private static final CaptionStyle UNSPECIFIED; 389 390 /** The default caption style used to fill in unspecified values. @hide */ 391 public static final CaptionStyle DEFAULT; 392 393 /** @hide */ 394 @UnsupportedAppUsage 395 public static final CaptionStyle[] PRESETS; 396 397 /** @hide */ 398 public static final int PRESET_CUSTOM = -1; 399 400 /** Unspecified edge type value. */ 401 public static final int EDGE_TYPE_UNSPECIFIED = -1; 402 403 /** Edge type value specifying no character edges. */ 404 public static final int EDGE_TYPE_NONE = 0; 405 406 /** Edge type value specifying uniformly outlined character edges. */ 407 public static final int EDGE_TYPE_OUTLINE = 1; 408 409 /** Edge type value specifying drop-shadowed character edges. */ 410 public static final int EDGE_TYPE_DROP_SHADOW = 2; 411 412 /** Edge type value specifying raised bevel character edges. */ 413 public static final int EDGE_TYPE_RAISED = 3; 414 415 /** Edge type value specifying depressed bevel character edges. */ 416 public static final int EDGE_TYPE_DEPRESSED = 4; 417 418 /** The preferred foreground color for video captions. */ 419 public final int foregroundColor; 420 421 /** The preferred background color for video captions. */ 422 public final int backgroundColor; 423 424 /** 425 * The preferred edge type for video captions, one of: 426 * <ul> 427 * <li>{@link #EDGE_TYPE_UNSPECIFIED} 428 * <li>{@link #EDGE_TYPE_NONE} 429 * <li>{@link #EDGE_TYPE_OUTLINE} 430 * <li>{@link #EDGE_TYPE_DROP_SHADOW} 431 * <li>{@link #EDGE_TYPE_RAISED} 432 * <li>{@link #EDGE_TYPE_DEPRESSED} 433 * </ul> 434 */ 435 public final int edgeType; 436 437 /** 438 * The preferred edge color for video captions, if using an edge type 439 * other than {@link #EDGE_TYPE_NONE}. 440 */ 441 public final int edgeColor; 442 443 /** The preferred window color for video captions. */ 444 public final int windowColor; 445 446 /** 447 * @hide 448 */ 449 public final String mRawTypeface; 450 451 private final boolean mHasForegroundColor; 452 private final boolean mHasBackgroundColor; 453 private final boolean mHasEdgeType; 454 private final boolean mHasEdgeColor; 455 private final boolean mHasWindowColor; 456 457 /** Lazily-created typeface based on the raw typeface string. */ 458 private Typeface mParsedTypeface; 459 CaptionStyle(int foregroundColor, int backgroundColor, int edgeType, int edgeColor, int windowColor, String rawTypeface)460 private CaptionStyle(int foregroundColor, int backgroundColor, int edgeType, int edgeColor, 461 int windowColor, String rawTypeface) { 462 mHasForegroundColor = hasColor(foregroundColor); 463 mHasBackgroundColor = hasColor(backgroundColor); 464 mHasEdgeType = edgeType != EDGE_TYPE_UNSPECIFIED; 465 mHasEdgeColor = hasColor(edgeColor); 466 mHasWindowColor = hasColor(windowColor); 467 468 // Always use valid colors, even when no override is specified, to 469 // ensure backwards compatibility with apps targeting KitKat MR2. 470 this.foregroundColor = mHasForegroundColor ? foregroundColor : Color.WHITE; 471 this.backgroundColor = mHasBackgroundColor ? backgroundColor : Color.BLACK; 472 this.edgeType = mHasEdgeType ? edgeType : EDGE_TYPE_NONE; 473 this.edgeColor = mHasEdgeColor ? edgeColor : Color.BLACK; 474 this.windowColor = mHasWindowColor ? windowColor : COLOR_NONE_OPAQUE; 475 476 mRawTypeface = rawTypeface; 477 } 478 479 /** 480 * Returns whether a packed color indicates a non-default value. 481 * 482 * @param packedColor the packed color value 483 * @return {@code true} if a non-default value is specified 484 * @hide 485 */ hasColor(int packedColor)486 public static boolean hasColor(int packedColor) { 487 // Matches the color packing code from Settings. "Default" packed 488 // colors are indicated by zero alpha and non-zero red/blue. The 489 // cached alpha value used by Settings is stored in green. 490 return (packedColor >>> 24) != 0 || (packedColor & 0xFFFF00) == 0; 491 } 492 493 /** 494 * Applies a caption style, overriding any properties that are specified 495 * in the overlay caption. 496 * 497 * @param overlay The style to apply 498 * @return A caption style with the overlay style applied 499 * @hide 500 */ 501 @NonNull applyStyle(@onNull CaptionStyle overlay)502 public CaptionStyle applyStyle(@NonNull CaptionStyle overlay) { 503 final int newForegroundColor = overlay.hasForegroundColor() ? 504 overlay.foregroundColor : foregroundColor; 505 final int newBackgroundColor = overlay.hasBackgroundColor() ? 506 overlay.backgroundColor : backgroundColor; 507 final int newEdgeType = overlay.hasEdgeType() ? 508 overlay.edgeType : edgeType; 509 final int newEdgeColor = overlay.hasEdgeColor() ? 510 overlay.edgeColor : edgeColor; 511 final int newWindowColor = overlay.hasWindowColor() ? 512 overlay.windowColor : windowColor; 513 final String newRawTypeface = overlay.mRawTypeface != null ? 514 overlay.mRawTypeface : mRawTypeface; 515 return new CaptionStyle(newForegroundColor, newBackgroundColor, newEdgeType, 516 newEdgeColor, newWindowColor, newRawTypeface); 517 } 518 519 /** 520 * @return {@code true} if the user has specified a background color 521 * that should override the application default, {@code false} 522 * otherwise 523 */ hasBackgroundColor()524 public boolean hasBackgroundColor() { 525 return mHasBackgroundColor; 526 } 527 528 /** 529 * @return {@code true} if the user has specified a foreground color 530 * that should override the application default, {@code false} 531 * otherwise 532 */ hasForegroundColor()533 public boolean hasForegroundColor() { 534 return mHasForegroundColor; 535 } 536 537 /** 538 * @return {@code true} if the user has specified an edge type that 539 * should override the application default, {@code false} 540 * otherwise 541 */ hasEdgeType()542 public boolean hasEdgeType() { 543 return mHasEdgeType; 544 } 545 546 /** 547 * @return {@code true} if the user has specified an edge color that 548 * should override the application default, {@code false} 549 * otherwise 550 */ hasEdgeColor()551 public boolean hasEdgeColor() { 552 return mHasEdgeColor; 553 } 554 555 /** 556 * @return {@code true} if the user has specified a window color that 557 * should override the application default, {@code false} 558 * otherwise 559 */ hasWindowColor()560 public boolean hasWindowColor() { 561 return mHasWindowColor; 562 } 563 564 /** 565 * @return the preferred {@link Typeface} for video captions, or null if 566 * not specified 567 */ 568 @Nullable getTypeface()569 public Typeface getTypeface() { 570 if (mParsedTypeface == null && !TextUtils.isEmpty(mRawTypeface)) { 571 mParsedTypeface = Typeface.create(mRawTypeface, Typeface.NORMAL); 572 } 573 return mParsedTypeface; 574 } 575 576 /** 577 * @hide 578 */ 579 @NonNull getCustomStyle(ContentResolver cr)580 public static CaptionStyle getCustomStyle(ContentResolver cr) { 581 final CaptionStyle defStyle = CaptionStyle.DEFAULT_CUSTOM; 582 final int foregroundColor = Secure.getInt( 583 cr, Secure.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR, defStyle.foregroundColor); 584 final int backgroundColor = Secure.getInt( 585 cr, Secure.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR, defStyle.backgroundColor); 586 final int edgeType = Secure.getInt( 587 cr, Secure.ACCESSIBILITY_CAPTIONING_EDGE_TYPE, defStyle.edgeType); 588 final int edgeColor = Secure.getInt( 589 cr, Secure.ACCESSIBILITY_CAPTIONING_EDGE_COLOR, defStyle.edgeColor); 590 final int windowColor = Secure.getInt( 591 cr, Secure.ACCESSIBILITY_CAPTIONING_WINDOW_COLOR, defStyle.windowColor); 592 593 String rawTypeface = Secure.getString(cr, Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE); 594 if (rawTypeface == null) { 595 rawTypeface = defStyle.mRawTypeface; 596 } 597 598 return new CaptionStyle(foregroundColor, backgroundColor, edgeType, edgeColor, 599 windowColor, rawTypeface); 600 } 601 602 static { 603 WHITE_ON_BLACK = new CaptionStyle(Color.WHITE, Color.BLACK, EDGE_TYPE_NONE, 604 Color.BLACK, COLOR_NONE_OPAQUE, null); 605 BLACK_ON_WHITE = new CaptionStyle(Color.BLACK, Color.WHITE, EDGE_TYPE_NONE, 606 Color.BLACK, COLOR_NONE_OPAQUE, null); 607 YELLOW_ON_BLACK = new CaptionStyle(Color.YELLOW, Color.BLACK, EDGE_TYPE_NONE, 608 Color.BLACK, COLOR_NONE_OPAQUE, null); 609 YELLOW_ON_BLUE = new CaptionStyle(Color.YELLOW, Color.BLUE, EDGE_TYPE_NONE, 610 Color.BLACK, COLOR_NONE_OPAQUE, null); 611 UNSPECIFIED = new CaptionStyle(COLOR_UNSPECIFIED, COLOR_UNSPECIFIED, 612 EDGE_TYPE_UNSPECIFIED, COLOR_UNSPECIFIED, COLOR_UNSPECIFIED, null); 613 614 // The ordering of these cannot change since we store the index 615 // directly in preferences. 616 PRESETS = new CaptionStyle[] { 617 WHITE_ON_BLACK, BLACK_ON_WHITE, YELLOW_ON_BLACK, YELLOW_ON_BLUE, UNSPECIFIED 618 }; 619 620 DEFAULT_CUSTOM = WHITE_ON_BLACK; 621 DEFAULT = WHITE_ON_BLACK; 622 } 623 } 624 625 /** 626 * Listener for changes in captioning properties, including enabled state 627 * and user style preferences. 628 */ 629 public static abstract class CaptioningChangeListener { 630 /** 631 * Called when the captioning enabled state changes. 632 * 633 * @param enabled the user's new preferred captioning enabled state 634 */ onEnabledChanged(boolean enabled)635 public void onEnabledChanged(boolean enabled) {} 636 637 /** 638 * Called when the captioning user style changes. 639 * 640 * @param userStyle the user's new preferred style 641 * @see CaptioningManager#getUserStyle() 642 */ onUserStyleChanged(@onNull CaptionStyle userStyle)643 public void onUserStyleChanged(@NonNull CaptionStyle userStyle) {} 644 645 /** 646 * Called when the captioning locale changes. 647 * 648 * @param locale the preferred captioning locale, or {@code null} if not specified 649 * @see CaptioningManager#getLocale() 650 */ onLocaleChanged(@ullable Locale locale)651 public void onLocaleChanged(@Nullable Locale locale) {} 652 653 /** 654 * Called when the captioning font scaling factor changes. 655 * 656 * @param fontScale the preferred font scaling factor 657 * @see CaptioningManager#getFontScale() 658 */ onFontScaleChanged(float fontScale)659 public void onFontScaleChanged(float fontScale) {} 660 661 662 /** 663 * Called when the system audio caption enabled state changes. 664 * 665 * @param enabled the system audio caption enabled state 666 */ onSystemAudioCaptioningChanged(boolean enabled)667 public void onSystemAudioCaptioningChanged(boolean enabled) {} 668 669 /** 670 * Called when the system audio caption UI enabled state changes. 671 * 672 * @param enabled the system audio caption UI enabled state 673 */ onSystemAudioCaptioningUiChanged(boolean enabled)674 public void onSystemAudioCaptioningUiChanged(boolean enabled) {} 675 } 676 677 /** 678 * Interface for accessing the system audio captioning related secure setting keys. 679 * 680 * @hide 681 */ 682 public interface SystemAudioCaptioningAccessing { 683 /** 684 * Sets the system audio caption enabled state. 685 * 686 * @param isEnabled The system audio captioning enabled state. 687 * @param userId The user Id. 688 */ setSystemAudioCaptioningEnabled(boolean isEnabled, int userId)689 void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId); 690 691 /** 692 * Gets the system audio caption UI enabled state. 693 * 694 * @param userId The user Id. 695 * @return the system audio caption UI enabled state. 696 */ isSystemAudioCaptioningUiEnabled(int userId)697 boolean isSystemAudioCaptioningUiEnabled(int userId); 698 699 /** 700 * Sets the system audio caption UI enabled state. 701 * 702 * @param isEnabled The system audio captioning UI enabled state. 703 * @param userId The user Id. 704 */ setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId)705 void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId); 706 } 707 } 708