1 /* 2 * Copyright (C) 2021 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.car.evs; 18 19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE; 20 21 import android.annotation.CallbackExecutor; 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.RequiresPermission; 26 import android.annotation.SuppressLint; 27 import android.annotation.SystemApi; 28 import android.car.Car; 29 import android.car.CarManagerBase; 30 import android.car.annotation.AddedInOrBefore; 31 import android.car.annotation.ApiRequirements; 32 import android.car.annotation.RequiredFeature; 33 import android.car.builtin.util.Slogf; 34 import android.os.Binder; 35 import android.os.IBinder; 36 import android.os.RemoteException; 37 import android.util.Log; 38 import android.util.SparseArray; 39 40 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 41 import com.android.car.internal.evs.CarEvsUtils; 42 import com.android.internal.annotations.GuardedBy; 43 44 import java.lang.annotation.Retention; 45 import java.lang.annotation.RetentionPolicy; 46 import java.lang.ref.WeakReference; 47 import java.util.Objects; 48 import java.util.concurrent.Executor; 49 import java.util.concurrent.Semaphore; 50 import java.util.concurrent.TimeUnit; 51 52 /** 53 * Provides an application interface for interativing with the Extended View System service. 54 * 55 * @hide 56 */ 57 @RequiredFeature(Car.CAR_EVS_SERVICE) 58 @SystemApi 59 public final class CarEvsManager extends CarManagerBase { 60 @AddedInOrBefore(majorVersion = 33) 61 public static final String EXTRA_SESSION_TOKEN = "android.car.evs.extra.SESSION_TOKEN"; 62 63 private static final String TAG = CarEvsManager.class.getSimpleName(); 64 private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 65 66 private final ICarEvsService mService; 67 private final Object mStreamLock = new Object(); 68 69 // This array maintains mappings between service type and its client. 70 @GuardedBy("mStreamLock") 71 private SparseArray<CarEvsStreamCallback> mStreamCallbacks = new SparseArray<>(); 72 73 @GuardedBy("mStreamLock") 74 private Executor mStreamCallbackExecutor; 75 76 private final CarEvsStreamListenerToService mStreamListenerToService = 77 new CarEvsStreamListenerToService(this); 78 79 private final Object mStatusLock = new Object(); 80 81 @GuardedBy("mStatusLock") 82 private CarEvsStatusListener mStatusListener; 83 84 @GuardedBy("mStatusLock") 85 private Executor mStatusListenerExecutor; 86 87 private final CarEvsStatusListenerToService mStatusListenerToService = 88 new CarEvsStatusListenerToService(this); 89 90 /** 91 * Service type to represent the rearview camera service. 92 */ 93 @AddedInOrBefore(majorVersion = 33) 94 public static final int SERVICE_TYPE_REARVIEW = 0; 95 96 /** 97 * Service type to represent the surround view service. 98 */ 99 @AddedInOrBefore(majorVersion = 33) 100 public static final int SERVICE_TYPE_SURROUNDVIEW = 1; 101 102 /** 103 * Service type to represent the front exterior view camera service. 104 */ 105 @ApiRequirements(minCarVersion = 106 ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, 107 minPlatformVersion = 108 ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) 109 public static final int SERVICE_TYPE_FRONTVIEW = 2; 110 111 /** 112 * Service type to represent the left exterior view camera service such as 113 * the virtual side mirror. 114 */ 115 @ApiRequirements(minCarVersion = 116 ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, 117 minPlatformVersion = 118 ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) 119 public static final int SERVICE_TYPE_LEFTVIEW = 3; 120 121 /** 122 * Service type to represent the right exterior view camera service such as 123 * the virtual side mirror. 124 */ 125 @ApiRequirements(minCarVersion = 126 ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, 127 minPlatformVersion = 128 ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) 129 public static final int SERVICE_TYPE_RIGHTVIEW = 4; 130 131 /** 132 * Service type to represent the camera service that captures the scene 133 * with the driver. 134 */ 135 @ApiRequirements(minCarVersion = 136 ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, 137 minPlatformVersion = 138 ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) 139 public static final int SERVICE_TYPE_DRIVERVIEW = 5; 140 141 /** 142 * Service type to represent the camera service that captures the scene 143 * with the front-seat passengers. 144 */ 145 @ApiRequirements(minCarVersion = 146 ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, 147 minPlatformVersion = 148 ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) 149 public static final int SERVICE_TYPE_FRONT_PASSENGERSVIEW = 6; 150 151 /** 152 * Service type to represent the camera service that captures the scene 153 * with the rear-seat passengers. 154 */ 155 @ApiRequirements(minCarVersion = 156 ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, 157 minPlatformVersion = 158 ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) 159 public static final int SERVICE_TYPE_REAR_PASSENGERSVIEW = 7; 160 161 /** 162 * Service type to represent the camera service that captures the scene 163 * the user defines. 164 */ 165 @ApiRequirements(minCarVersion = 166 ApiRequirements.CarVersion.UPSIDE_DOWN_CAKE_0, 167 minPlatformVersion = 168 ApiRequirements.PlatformVersion.UPSIDE_DOWN_CAKE_0) 169 public static final int SERVICE_TYPE_USER_DEFINED = 1000; 170 171 /** @hide */ 172 @IntDef (prefix = {"SERVICE_TYPE_"}, value = { 173 SERVICE_TYPE_REARVIEW, 174 SERVICE_TYPE_SURROUNDVIEW, 175 SERVICE_TYPE_FRONTVIEW, 176 SERVICE_TYPE_LEFTVIEW, 177 SERVICE_TYPE_RIGHTVIEW, 178 SERVICE_TYPE_DRIVERVIEW, 179 SERVICE_TYPE_FRONT_PASSENGERSVIEW, 180 SERVICE_TYPE_REAR_PASSENGERSVIEW, 181 SERVICE_TYPE_USER_DEFINED, 182 }) 183 @Retention(RetentionPolicy.SOURCE) 184 public @interface CarEvsServiceType {} 185 186 /** 187 * State that a corresponding service type is not available. 188 */ 189 @AddedInOrBefore(majorVersion = 33) 190 public static final int SERVICE_STATE_UNAVAILABLE = 0; 191 192 /** 193 * State that a corresponding service type is inactive; it's available but not used 194 * by any clients. 195 */ 196 @AddedInOrBefore(majorVersion = 33) 197 public static final int SERVICE_STATE_INACTIVE = 1; 198 199 /** 200 * State that CarEvsManager received a service request from the client. 201 */ 202 @AddedInOrBefore(majorVersion = 33) 203 public static final int SERVICE_STATE_REQUESTED = 2; 204 205 /** 206 * State that a corresponding service type is actively being used. 207 */ 208 @AddedInOrBefore(majorVersion = 33) 209 public static final int SERVICE_STATE_ACTIVE = 3; 210 211 /** @hide */ 212 @IntDef (prefix = {"SERVICE_STATE_"}, value = { 213 SERVICE_STATE_UNAVAILABLE, 214 SERVICE_STATE_INACTIVE, 215 SERVICE_STATE_REQUESTED, 216 SERVICE_STATE_ACTIVE 217 }) 218 @Retention(RetentionPolicy.SOURCE) 219 public @interface CarEvsServiceState {} 220 221 /** 222 * This is a default EVS stream event type. 223 */ 224 @AddedInOrBefore(majorVersion = 33) 225 public static final int STREAM_EVENT_NONE = 0; 226 227 /** 228 * EVS stream event to notify a video stream has been started. 229 */ 230 @AddedInOrBefore(majorVersion = 33) 231 public static final int STREAM_EVENT_STREAM_STARTED = 1; 232 233 /** 234 * EVS stream event to notify a video stream has been stopped. 235 */ 236 @AddedInOrBefore(majorVersion = 33) 237 public static final int STREAM_EVENT_STREAM_STOPPED = 2; 238 239 /** 240 * EVS stream event to notify that a video stream is dropped. 241 */ 242 @AddedInOrBefore(majorVersion = 33) 243 public static final int STREAM_EVENT_FRAME_DROPPED = 3; 244 245 /** 246 * EVS stream event occurs when a timer for a new frame's arrival is expired. 247 */ 248 @AddedInOrBefore(majorVersion = 33) 249 public static final int STREAM_EVENT_TIMEOUT = 4; 250 251 /** 252 * EVS stream event occurs when a camera parameter is changed. 253 */ 254 @AddedInOrBefore(majorVersion = 33) 255 public static final int STREAM_EVENT_PARAMETER_CHANGED = 5; 256 257 /** 258 * EVS stream event to notify the primary owner has been changed. 259 */ 260 @AddedInOrBefore(majorVersion = 33) 261 public static final int STREAM_EVENT_PRIMARY_OWNER_CHANGED = 6; 262 263 /** 264 * Other EVS stream errors 265 */ 266 @AddedInOrBefore(majorVersion = 33) 267 public static final int STREAM_EVENT_OTHER_ERRORS = 7; 268 269 /** @hide */ 270 @IntDef(prefix = {"STREAM_EVENT_"}, value = { 271 STREAM_EVENT_NONE, 272 STREAM_EVENT_STREAM_STARTED, 273 STREAM_EVENT_STREAM_STOPPED, 274 STREAM_EVENT_FRAME_DROPPED, 275 STREAM_EVENT_TIMEOUT, 276 STREAM_EVENT_PARAMETER_CHANGED, 277 STREAM_EVENT_PRIMARY_OWNER_CHANGED, 278 STREAM_EVENT_OTHER_ERRORS 279 }) 280 @Retention(RetentionPolicy.SOURCE) 281 public @interface CarEvsStreamEvent {} 282 283 /** 284 * Status to tell that a request is successfully processed. 285 */ 286 @AddedInOrBefore(majorVersion = 33) 287 public static final int ERROR_NONE = 0; 288 289 /** 290 * Status to tell a requested service is not available. 291 */ 292 @AddedInOrBefore(majorVersion = 33) 293 public static final int ERROR_UNAVAILABLE = -1; 294 295 /** 296 * Status to tell CarEvsService is busy to serve the privileged client. 297 */ 298 @AddedInOrBefore(majorVersion = 33) 299 public static final int ERROR_BUSY = -2; 300 301 /** @hide */ 302 @IntDef(prefix = {"ERROR_"}, value = { 303 ERROR_NONE, 304 ERROR_UNAVAILABLE, 305 ERROR_BUSY 306 }) 307 @Retention(RetentionPolicy.SOURCE) 308 public @interface CarEvsError {} 309 310 /** 311 * Gets an instance of CarEvsManager 312 * 313 * CarEvsManager manages {@link com.android.car.evs.CarEvsService} and provides APIs that the 314 * clients can use the Extended View System service. 315 * 316 * This must not be obtained directly by clients, use {@link Car#getCarManager(String)} instead. 317 * 318 * @hide 319 */ CarEvsManager(Car car, IBinder service)320 public CarEvsManager(Car car, IBinder service) { 321 super(car); 322 323 // Gets CarEvsService 324 mService = ICarEvsService.Stub.asInterface(service); 325 } 326 327 /** @hide */ 328 @Override 329 @AddedInOrBefore(majorVersion = 33) onCarDisconnected()330 public void onCarDisconnected() { 331 synchronized (mStatusLock) { 332 mStatusListener = null; 333 mStatusListenerExecutor = null; 334 } 335 336 synchronized (mStreamLock) { 337 stopVideoStreamLocked(); 338 } 339 } 340 341 /** 342 * Application registers {@link #CarEvsStatusListener} object to receive requests to control 343 * the activity and monitor the status of the EVS service. 344 */ 345 public interface CarEvsStatusListener { 346 /** 347 * Called when the status of EVS service is changed. 348 * 349 * @param type A type of EVS service; e.g. the rearview. 350 * @param state Updated service state; e.g. the service is started. 351 */ 352 @AddedInOrBefore(majorVersion = 33) onStatusChanged(@onNull CarEvsStatus status)353 void onStatusChanged(@NonNull CarEvsStatus status); 354 } 355 356 /** 357 * Class implementing the listener interface {@link com.android.car.ICarEvsStatusListener} 358 * to listen status updates across the binder interface. 359 */ 360 private static class CarEvsStatusListenerToService extends ICarEvsStatusListener.Stub { 361 private final WeakReference<CarEvsManager> mManager; 362 CarEvsStatusListenerToService(CarEvsManager manager)363 CarEvsStatusListenerToService(CarEvsManager manager) { 364 mManager = new WeakReference<>(manager); 365 } 366 367 @Override onStatusChanged(@onNull CarEvsStatus status)368 public void onStatusChanged(@NonNull CarEvsStatus status) { 369 Objects.requireNonNull(status); 370 371 CarEvsManager mgr = mManager.get(); 372 if (mgr != null) { 373 mgr.handleServiceStatusChanged(status); 374 } 375 } 376 } 377 378 /** 379 * Gets the {@link #CarEvsStatus} from the service listener {@link 380 * #CarEvsStatusListenerToService} and forwards it to the client. 381 * 382 * @param status {@link android.car.evs.CarEvsStatus} 383 */ handleServiceStatusChanged(CarEvsStatus status)384 private void handleServiceStatusChanged(CarEvsStatus status) { 385 if (DBG) { 386 Slogf.d(TAG, "Service state changed: service = " + status.getServiceType() 387 + ", state = " + status.getState()); 388 } 389 390 final CarEvsStatusListener listener; 391 final Executor executor; 392 synchronized (mStatusLock) { 393 listener = mStatusListener; 394 executor = mStatusListenerExecutor; 395 } 396 397 if (listener != null) { 398 executor.execute(() -> listener.onStatusChanged(status)); 399 } else if (DBG) { 400 Slogf.w(TAG, "No client seems active; a received event is ignored."); 401 } 402 } 403 404 /** 405 * Sets {@link #CarEvsStatusListener} object to receive requests to control the activity 406 * view and EVS data. 407 * 408 * @param executor {@link java.util.concurrent.Executor} to execute callbacks. 409 * @param listener {@link #CarEvsStatusListener} to register. 410 * @throws IllegalStateException if this method is called while a registered status listener 411 * exists. 412 */ 413 @RequiresPermission(Car.PERMISSION_MONITOR_CAR_EVS_STATUS) 414 @AddedInOrBefore(majorVersion = 33) setStatusListener(@onNull @allbackExecutor Executor executor, @NonNull CarEvsStatusListener listener)415 public void setStatusListener(@NonNull @CallbackExecutor Executor executor, 416 @NonNull CarEvsStatusListener listener) { 417 if (DBG) { 418 Slogf.d(TAG, "Registering a service monitoring listener."); 419 } 420 421 Objects.requireNonNull(listener); 422 Objects.requireNonNull(executor); 423 424 if (mStatusListener != null) { 425 throw new IllegalStateException("A status listener is already registered."); 426 } 427 428 synchronized (mStatusLock) { 429 mStatusListener = listener; 430 mStatusListenerExecutor = executor; 431 } 432 433 try { 434 mService.registerStatusListener(mStatusListenerToService); 435 } catch (RemoteException err) { 436 handleRemoteExceptionFromCarService(err); 437 } 438 } 439 440 /** 441 * Stops getting callbacks to control the camera viewing activity by clearing 442 * {@link #CarEvsStatusListener} object. 443 */ 444 @RequiresPermission(Car.PERMISSION_MONITOR_CAR_EVS_STATUS) 445 @AddedInOrBefore(majorVersion = 33) clearStatusListener()446 public void clearStatusListener() { 447 if (DBG) { 448 Slogf.d(TAG, "Unregistering a service monitoring callback."); 449 } 450 451 synchronized (mStatusLock) { 452 mStatusListener = null; 453 } 454 455 try{ 456 mService.unregisterStatusListener(mStatusListenerToService); 457 } catch (RemoteException err) { 458 handleRemoteExceptionFromCarService(err); 459 } 460 } 461 462 /** 463 * Application registers {@link #CarEvsStreamCallback} object to listen to EVS services' status 464 * changes. 465 * 466 * CarEvsManager supports two client types; one is a System UI type client and another is a 467 * normal Android activity type client. The former client type has a priority over 468 * the latter type client and CarEvsManager allows only a single client of each type to 469 * subscribe. 470 */ 471 // TODO(b/174572385): Removes below lint suppression 472 @SuppressLint("CallbackInterface") 473 public interface CarEvsStreamCallback { 474 /** 475 * Called when any EVS stream events occur. 476 * 477 * @param event {@link #CarEvsStreamEvent}; e.g. a stream started 478 */ 479 @AddedInOrBefore(majorVersion = 33) 480 @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE) onStreamEvent(@arEvsStreamEvent int event)481 default void onStreamEvent(@CarEvsStreamEvent int event) {} 482 483 /** 484 * Called when new frame arrives. 485 * 486 * @param buffer {@link android.car.evs.CarEvsBufferDescriptor} contains a EVS frame 487 */ 488 @AddedInOrBefore(majorVersion = 33) 489 @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE) onNewFrame(@onNull CarEvsBufferDescriptor buffer)490 default void onNewFrame(@NonNull CarEvsBufferDescriptor buffer) {} 491 } 492 493 /** 494 * Class implementing the listener interface and gets callbacks from the 495 * {@link com.android.car.ICarEvsStreamCallback} across the binder interface. 496 */ 497 private static class CarEvsStreamListenerToService extends ICarEvsStreamCallback.Stub { 498 private static final int DEFAULT_STREAM_EVENT_WAIT_TIMEOUT_IN_SEC = 1; 499 private final WeakReference<CarEvsManager> mManager; 500 private final Semaphore mStreamEventOccurred = new Semaphore(/* permits= */ 0); 501 private @CarEvsStreamEvent int mLastStreamEvent; 502 CarEvsStreamListenerToService(CarEvsManager manager)503 CarEvsStreamListenerToService(CarEvsManager manager) { 504 mManager = new WeakReference<>(manager); 505 } 506 507 @Override onStreamEvent(@arEvsStreamEvent int event)508 public void onStreamEvent(@CarEvsStreamEvent int event) { 509 mLastStreamEvent = event; 510 mStreamEventOccurred.release(); 511 512 CarEvsManager manager = mManager.get(); 513 if (manager != null) { 514 manager.handleStreamEvent(event); 515 } 516 } 517 518 @Override onNewFrame(CarEvsBufferDescriptor buffer)519 public void onNewFrame(CarEvsBufferDescriptor buffer) { 520 CarEvsManager manager = mManager.get(); 521 if (manager != null) { 522 manager.handleNewFrame(buffer); 523 } 524 } 525 waitForStreamEvent(@arEvsStreamEvent int expected)526 public boolean waitForStreamEvent(@CarEvsStreamEvent int expected) { 527 return waitForStreamEvent(expected, DEFAULT_STREAM_EVENT_WAIT_TIMEOUT_IN_SEC); 528 } 529 waitForStreamEvent(@arEvsStreamEvent int expected, int timeoutInSeconds)530 public boolean waitForStreamEvent(@CarEvsStreamEvent int expected, int timeoutInSeconds) { 531 while (true) { 532 try { 533 if (!mStreamEventOccurred.tryAcquire(timeoutInSeconds, TimeUnit.SECONDS)) { 534 Slogf.w(TAG, "Timer for a new stream event expired."); 535 return false; 536 } 537 538 if (mLastStreamEvent == expected) { 539 return true; 540 } 541 } catch (InterruptedException e) { 542 Slogf.w(TAG, "Interrupted while waiting for an event %d.\nException = %s", 543 expected, Log.getStackTraceString(e)); 544 return false; 545 } 546 } 547 } 548 } 549 550 /** 551 * Gets the {@link #CarEvsStreamEvent} from the service listener 552 * {@link #CarEvsStreamListenerToService} and dispatches it to an executor provided 553 * to the manager. 554 * 555 * @param event {@link #CarEvsStreamEvent} from the service this manager subscribes to. 556 */ handleStreamEvent(@arEvsStreamEvent int event)557 private void handleStreamEvent(@CarEvsStreamEvent int event) { 558 synchronized(mStreamLock) { 559 handleStreamEventLocked(event); 560 } 561 } 562 563 @GuardedBy("mStreamLock") handleStreamEventLocked(@arEvsStreamEvent int event)564 private void handleStreamEventLocked(@CarEvsStreamEvent int event) { 565 if (DBG) { 566 Slogf.d(TAG, "Received: " + event); 567 } 568 569 CarEvsStreamCallback callback = mStreamCallbacks.get(CarEvsUtils.getTag(event)); 570 Executor executor = mStreamCallbackExecutor; 571 if (callback != null) { 572 executor.execute(() -> callback.onStreamEvent(CarEvsUtils.getValue(event))); 573 } else if (DBG) { 574 Slogf.w(TAG, "No client seems active; a current stream event is ignored."); 575 } 576 } 577 578 /** 579 * Gets the {@link android.car.evs.CarEvsBufferDescriptor} from the service listener 580 * {@link #CarEvsStreamListenerToService} and dispatches it to an executor provided 581 * to the manager. 582 * 583 * @param buffer {@link android.car.evs.CarEvsBufferDescriptor} 584 */ handleNewFrame(@onNull CarEvsBufferDescriptor buffer)585 private void handleNewFrame(@NonNull CarEvsBufferDescriptor buffer) { 586 Objects.requireNonNull(buffer); 587 if (DBG) { 588 Slogf.d(TAG, "Received a buffer: " + buffer); 589 } 590 591 final CarEvsStreamCallback callback; 592 final Executor executor; 593 synchronized (mStreamLock) { 594 callback = mStreamCallbacks.get(CarEvsUtils.getTag(buffer.getId())); 595 executor = mStreamCallbackExecutor; 596 } 597 598 if (callback != null) { 599 executor.execute(() -> callback.onNewFrame(buffer)); 600 } else { 601 if (DBG) { 602 Slogf.w(TAG, "A buffer is being returned back to the service because no active " 603 + "clients exist."); 604 } 605 returnFrameBuffer(buffer); 606 } 607 } 608 609 610 /** Stops all active stream callbacks. */ 611 @GuardedBy("mStreamLock") stopVideoStreamLocked()612 private void stopVideoStreamLocked() { 613 if (mStreamCallbacks.size() < 1) { 614 Slogf.i(TAG, "No stream to stop."); 615 return; 616 } 617 618 try { 619 mService.stopVideoStream(mStreamListenerToService); 620 } catch (RemoteException err) { 621 handleRemoteExceptionFromCarService(err); 622 } 623 624 // Wait for a confirmation. 625 if (!mStreamListenerToService.waitForStreamEvent(STREAM_EVENT_STREAM_STOPPED)) { 626 Slogf.w(TAG, "EVS did not notify us that target streams are stopped " + 627 "before a time expires."); 628 } 629 630 // Notify clients that streams are stopped. 631 handleStreamEventLocked(STREAM_EVENT_STREAM_STOPPED); 632 633 // We're not interested in frames and events anymore. The client can safely assume 634 // the service is stopped properly. 635 mStreamCallbacks.clear(); 636 mStreamCallbackExecutor = null; 637 } 638 639 /** 640 * Returns a consumed {@link android.car.evs.CarEvsBufferDescriptor}. 641 * 642 * @param buffer {@link android.car.evs.CarEvsBufferDescriptor} to be returned to 643 * the EVS service. 644 */ 645 @RequiresPermission(Car.PERMISSION_USE_CAR_EVS_CAMERA) 646 @AddedInOrBefore(majorVersion = 33) returnFrameBuffer(@onNull CarEvsBufferDescriptor buffer)647 public void returnFrameBuffer(@NonNull CarEvsBufferDescriptor buffer) { 648 Objects.requireNonNull(buffer); 649 try { 650 mService.returnFrameBuffer(buffer); 651 } catch (RemoteException err) { 652 handleRemoteExceptionFromCarService(err); 653 } finally { 654 // We are done with this HardwareBuffer object. 655 buffer.getHardwareBuffer().close(); 656 } 657 } 658 659 /** 660 * Requests the system to start an activity for {@link #CarEvsServiceType}. 661 * 662 * @param type A type of EVS service to start. 663 * @return {@link #CarEvsError} to tell the result of the request. 664 * {@link #ERROR_UNAVAILABLE} will be returned if the CarEvsService is not connected to 665 * the native EVS service or the binder transaction fails. 666 * {@link #ERROR_BUSY} will be returned if the CarEvsService is in the 667 * {@link #SERVICE_STATE_REQUESTED} for a different service type. 668 * If the same service type is running, this will return {@link #ERROR_NONE}. 669 * {@link #ERROR_NONE} will be returned for all other cases. 670 */ 671 @RequiresPermission(Car.PERMISSION_REQUEST_CAR_EVS_ACTIVITY) 672 @AddedInOrBefore(majorVersion = 33) startActivity(@arEvsServiceType int type)673 public @CarEvsError int startActivity(@CarEvsServiceType int type) { 674 try { 675 return mService.startActivity(type); 676 } catch (RemoteException err) { 677 handleRemoteExceptionFromCarService(err); 678 } 679 680 return ERROR_UNAVAILABLE; 681 } 682 683 /** 684 * Requests the system to stop a current activity launched via {@link #startActivity}. 685 */ 686 @RequiresPermission(Car.PERMISSION_REQUEST_CAR_EVS_ACTIVITY) 687 @AddedInOrBefore(majorVersion = 33) stopActivity()688 public void stopActivity() { 689 try { 690 mService.stopActivity(); 691 } catch (RemoteException err) { 692 handleRemoteExceptionFromCarService(err); 693 } 694 } 695 696 /** 697 * Requests to start a video stream from {@link #CarEvsServiceType}. 698 * 699 * @param type A type of EVS service. 700 * @param token A session token that is issued to privileged clients. SystemUI must obtain this 701 * token obtain this via {@link #generateSessionToken} and pass it to the activity, to 702 * prioritize its service requests. 703 * TODO(b/179517136): Defines an Intent extra 704 * @param callback {@link #CarEvsStreamCallback} to listen to the stream. 705 * @param executor {@link java.util.concurrent.Executor} to run a callback. 706 * @return {@link #CarEvsError} to tell the result of the request. 707 * {@link #ERROR_UNAVAILABLE} will be returned if the CarEvsService is not connected to 708 * the native EVS service or the binder transaction fails. 709 * {@link #ERROR_BUSY} will be returned if the CarEvsService is handling a service 710 * request with a valid session token. 711 * {@link #ERROR_NONE} for all other cases. 712 */ 713 @RequiresPermission(Car.PERMISSION_USE_CAR_EVS_CAMERA) 714 @AddedInOrBefore(majorVersion = 33) startVideoStream( @arEvsServiceType int type, @Nullable IBinder token, @NonNull @CallbackExecutor Executor executor, @NonNull CarEvsStreamCallback callback)715 public @CarEvsError int startVideoStream( 716 @CarEvsServiceType int type, 717 @Nullable IBinder token, 718 @NonNull @CallbackExecutor Executor executor, 719 @NonNull CarEvsStreamCallback callback) { 720 if (DBG) { 721 Slogf.d(TAG, "Received a request to start a video stream: " + type); 722 } 723 724 Objects.requireNonNull(executor); 725 Objects.requireNonNull(callback); 726 727 synchronized (mStreamLock) { 728 mStreamCallbacks.put(type, callback); 729 mStreamCallbackExecutor = executor; 730 } 731 732 int status = ERROR_UNAVAILABLE; 733 try { 734 // Requests the service to start a video stream 735 status = mService.startVideoStream(type, token, mStreamListenerToService); 736 } catch (RemoteException err) { 737 handleRemoteExceptionFromCarService(err); 738 } finally { 739 return status; 740 } 741 } 742 743 /** 744 * Requests to stop a current {@link #CarEvsServiceType}. 745 */ 746 @RequiresPermission(Car.PERMISSION_USE_CAR_EVS_CAMERA) 747 @AddedInOrBefore(majorVersion = 33) stopVideoStream()748 public void stopVideoStream() { 749 synchronized (mStreamLock) { 750 stopVideoStreamLocked(); 751 } 752 } 753 754 /** 755 * Queries the current status of CarEvsService 756 * 757 * @return {@link android.car.evs.CarEvsStatus} that describes current status of 758 * CarEvsService. 759 */ 760 @RequiresPermission(Car.PERMISSION_MONITOR_CAR_EVS_STATUS) 761 @NonNull 762 @AddedInOrBefore(majorVersion = 33) getCurrentStatus()763 public CarEvsStatus getCurrentStatus() { 764 try { 765 return mService.getCurrentStatus(); 766 } catch (RemoteException err) { 767 Slogf.e(TAG, "Failed to read a status of the service."); 768 return new CarEvsStatus(SERVICE_TYPE_REARVIEW, SERVICE_STATE_UNAVAILABLE); 769 } 770 } 771 772 /** 773 * Generates a service session token. 774 * 775 * @return {@link IBinder} object as a service session token. 776 */ 777 @RequiresPermission(Car.PERMISSION_CONTROL_CAR_EVS_ACTIVITY) 778 @NonNull 779 @AddedInOrBefore(majorVersion = 33) generateSessionToken()780 public IBinder generateSessionToken() { 781 IBinder token = null; 782 try { 783 token = mService.generateSessionToken(); 784 if (token == null) { 785 token = new Binder(); 786 } 787 } catch (RemoteException err) { 788 Slogf.e(TAG, "Failed to generate a session token."); 789 token = new Binder(); 790 } finally { 791 return token; 792 } 793 794 } 795 796 /** 797 * Returns whether or not a given service type is supported. 798 * 799 * @param type {@link CarEvsServiceType} to query 800 * @return true if a given service type is available on the system. 801 */ 802 @RequiresPermission(Car.PERMISSION_MONITOR_CAR_EVS_STATUS) 803 @AddedInOrBefore(majorVersion = 33) isSupported(@arEvsServiceType int type)804 public boolean isSupported(@CarEvsServiceType int type) { 805 try { 806 return mService.isSupported(type); 807 } catch (RemoteException err) { 808 Slogf.e(TAG, "Failed to query a service availability"); 809 return false; 810 } 811 } 812 } 813