/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.car.drivingstate; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.car.Car; import android.car.CarManagerBase; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.Log; import android.view.Display; import com.android.internal.annotations.GuardedBy; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.List; import java.util.Objects; /** * API to register and get the User Experience restrictions imposed based on the car's driving * state. */ public final class CarUxRestrictionsManager extends CarManagerBase { private static final String TAG = "CarUxRManager"; private static final boolean DBG = false; private static final boolean VDBG = false; private static final int MSG_HANDLE_UX_RESTRICTIONS_CHANGE = 0; /** * Baseline restriction mode is the default UX restrictions used for driving state. * * @hide */ public static final String UX_RESTRICTION_MODE_BASELINE = "baseline"; private int mDisplayId = Display.INVALID_DISPLAY; private final ICarUxRestrictionsManager mUxRService; private final EventCallbackHandler mEventCallbackHandler; @GuardedBy("this") private OnUxRestrictionsChangedListener mUxRListener; private CarUxRestrictionsChangeListenerToService mListenerToService; /** @hide */ public CarUxRestrictionsManager(Car car, IBinder service) { super(car); mUxRService = ICarUxRestrictionsManager.Stub.asInterface(service); mEventCallbackHandler = new EventCallbackHandler(this, getEventHandler().getLooper()); } /** @hide */ @Override public void onCarDisconnected() { mListenerToService = null; synchronized (this) { mUxRListener = null; } } /** * Listener Interface for clients to implement to get updated on driving state related * changes. */ public interface OnUxRestrictionsChangedListener { /** * Called when the UX restrictions due to a car's driving state changes. * * @param restrictionInfo The new UX restriction information */ void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo); } /** * Registers a {@link OnUxRestrictionsChangedListener} for listening to changes in the * UX Restrictions to adhere to. *
* If a listener has already been registered, it has to be unregistered before registering * the new one. * * @param listener {@link OnUxRestrictionsChangedListener} */ public void registerListener(@NonNull OnUxRestrictionsChangedListener listener) { registerListener(listener, getDisplayId()); } /** * @hide */ public void registerListener(@NonNull OnUxRestrictionsChangedListener listener, int displayId) { synchronized (this) { // Check if the listener has been already registered. if (mUxRListener != null) { if (DBG) { Log.d(TAG, "Listener already registered listener"); } return; } mUxRListener = listener; } try { if (mListenerToService == null) { mListenerToService = new CarUxRestrictionsChangeListenerToService(this); } // register to the Service to listen for changes. mUxRService.registerUxRestrictionsChangeListener(mListenerToService, displayId); } catch (RemoteException e) { handleRemoteExceptionFromCarService(e); } } /** * Unregisters the registered {@link OnUxRestrictionsChangedListener} */ public void unregisterListener() { synchronized (this) { if (mUxRListener == null) { if (DBG) { Log.d(TAG, "Listener was not previously registered"); } return; } mUxRListener = null; } try { mUxRService.unregisterUxRestrictionsChangeListener(mListenerToService); } catch (RemoteException e) { handleRemoteExceptionFromCarService(e); } } /** * Sets new {@link CarUxRestrictionsConfiguration}s for next trip. *
* Saving new configurations does not affect current configuration. The new configuration will * only be used after UX Restrictions service restarts when the vehicle is parked. *
* Input configurations must be one-to-one mapped to displays, namely each display must have
* exactly one configuration.
* See {@link CarUxRestrictionsConfiguration.Builder#setDisplayAddress(DisplayAddress)}.
*
* @param configs Map of display Id to UX restrictions configurations to be persisted.
* @return {@code true} if input config was successfully saved; {@code false} otherwise.
* @hide
*/
@RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
public boolean saveUxRestrictionsConfigurationForNextBoot(
List The default mode is {@link #UX_RESTRICTION_MODE_BASELINE}.
*
* If a new {@link CarUxRestrictions} is available upon mode transition, it'll
* be immediately dispatched to listeners.
*
* If the given mode is not configured for current driving state, it
* will fall back to the default value.
*
* If a configuration was set for a passenger mode before an upgrade to Android R, that
* passenger configuration is now called "passenger".
*
* @hide
*/
@RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
public boolean setRestrictionMode(@NonNull String mode) {
Objects.requireNonNull(mode, "mode must not be null");
try {
return mUxRService.setRestrictionMode(mode);
} catch (RemoteException e) {
return handleRemoteExceptionFromCarService(e, false);
}
}
/**
* Returns the current restriction mode.
*
* The default mode is {@link #UX_RESTRICTION_MODE_BASELINE}.
*
* If a configuration was set for a passenger mode before an upgrade to Android R, that
* passenger configuration is now called "passenger".
*
* @hide
*/
@RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
@NonNull
public String getRestrictionMode() {
try {
return mUxRService.getRestrictionMode();
} catch (RemoteException e) {
return handleRemoteExceptionFromCarService(e, null);
}
}
/**
* Sets a new {@link CarUxRestrictionsConfiguration} for next trip.
*
* Saving a new configuration does not affect current configuration. The new configuration will
* only be used after UX Restrictions service restarts when the vehicle is parked.
*
* @param config UX restrictions configuration to be persisted.
* @return {@code true} if input config was successfully saved; {@code false} otherwise.
* @hide
*/
@RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
public boolean saveUxRestrictionsConfigurationForNextBoot(
CarUxRestrictionsConfiguration config) {
return saveUxRestrictionsConfigurationForNextBoot(Arrays.asList(config));
}
/**
* Gets the staged configurations.
*
* Configurations set by {@link #saveUxRestrictionsConfigurationForNextBoot(List)} do not
* immediately affect current drive. Instead, they are staged to take effect when car service
* boots up the next time.
*
* This methods is only for test purpose, please do not use in production.
*
* @return current staged configuration, {@code null} if it's not available
* @hide
*/
@Nullable
@RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
public List