Merge "Implement display/voice interaction mediator" into sc-dev
diff --git a/service/src/com/android/car/power/PowerComponentHandler.java b/service/src/com/android/car/power/PowerComponentHandler.java
index 5d1c6cb..4598cb4 100644
--- a/service/src/com/android/car/power/PowerComponentHandler.java
+++ b/service/src/com/android/car/power/PowerComponentHandler.java
@@ -29,6 +29,8 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.wifi.WifiManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
@@ -36,6 +38,7 @@
import com.android.car.systeminterface.SystemInterface;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IVoiceInteractionManagerService;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -59,12 +62,14 @@
"forced_off_components";
private final Context mContext;
+ private final SystemInterface mSystemInterface;
private final AtomicFile mComponentStateFile;
private final SparseArray<PowerComponentMediator> mPowerComponentMediators =
new SparseArray<>();
PowerComponentHandler(Context context, SystemInterface systemInterface) {
mContext = context;
+ mSystemInterface = systemInterface;
mComponentStateFile = new AtomicFile(new File(systemInterface.getSystemCarDir(),
FORCED_OFF_COMPONENTS_FILENAME));
}
@@ -214,25 +219,28 @@
}
}
- private final class AudioPowerComponentMediator extends PowerComponentMediator {
- AudioPowerComponentMediator() {
- super(PowerComponent.AUDIO);
- }
- // TODO(b/162600135): implement turning on/off audio.
- }
-
- private final class MediaPowerComponentMediator extends PowerComponentMediator {
- MediaPowerComponentMediator() {
- super(PowerComponent.MEDIA);
- }
- // TODO(b/162600135): implement turning on/off media.
- }
-
+ // TODO(b/178824607): Check if power policy can turn on/off display as quickly as the existing
+ // implementation.
private final class DisplayPowerComponentMediator extends PowerComponentMediator {
DisplayPowerComponentMediator() {
super(PowerComponent.DISPLAY);
}
- // TODO(b/162600135): implement turning on/off display.
+
+ @Override
+ public boolean isComponentAvailable() {
+ // It is assumed that display is supported in all vehicles.
+ return true;
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ mSystemInterface.setDisplayState(enabled);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return mSystemInterface.isDisplayEnabled();
+ }
}
private final class WifiPowerComponentMediator extends PowerComponentMediator {
@@ -243,82 +251,57 @@
mWifiManager = mContext.getSystemService(WifiManager.class);
}
+ @Override
public boolean isComponentAvailable() {
PackageManager pm = mContext.getPackageManager();
return pm.hasSystemFeature(PackageManager.FEATURE_WIFI);
}
+ @Override
public void setEnabled(boolean enabled) {
mWifiManager.setWifiEnabled(enabled);
}
+ @Override
public boolean isEnabled() {
return mWifiManager.isWifiEnabled();
}
}
- private final class CellularPowerComponentMediator extends PowerComponentMediator {
- CellularPowerComponentMediator() {
- super(PowerComponent.CELLULAR);
- }
- // TODO(b/162600135): implement turning on/off cellular.
- }
-
- private final class EthernetPowerComponentMediator extends PowerComponentMediator {
- EthernetPowerComponentMediator() {
- super(PowerComponent.ETHERNET);
- }
- // TODO(b/162600135): implement turning on/off ethernet.
- }
-
- private final class ProjectionPowerComponentMediator extends PowerComponentMediator {
- ProjectionPowerComponentMediator() {
- super(PowerComponent.PROJECTION);
- }
- // TODO(b/162600135): implement turning on/off projection.
- }
-
- private final class NfcPowerComponentMediator extends PowerComponentMediator {
- NfcPowerComponentMediator() {
- super(PowerComponent.NFC);
- }
- // TODO(b/162600135): implement turning on/off nfc.
- }
-
- private final class InputPowerComponentMediator extends PowerComponentMediator {
- InputPowerComponentMediator() {
- super(PowerComponent.INPUT);
- }
- // TODO(b/162600135): implement turning on/off input.
- }
-
private final class VoiceInteractionPowerComponentMediator extends PowerComponentMediator {
+ private final IVoiceInteractionManagerService mVoiceInteractionManagerService;
+
+ private boolean mIsEnabled = true;
+
VoiceInteractionPowerComponentMediator() {
super(PowerComponent.VOICE_INTERACTION);
+ mVoiceInteractionManagerService = IVoiceInteractionManagerService.Stub.asInterface(
+ ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
}
- // TODO(b/162600135): implement turning on/off voice interaction.
- }
- private final class VisualInteractionPowerComponentMediator extends PowerComponentMediator {
- VisualInteractionPowerComponentMediator() {
- super(PowerComponent.VISUAL_INTERACTION);
+ @Override
+ public boolean isComponentAvailable() {
+ return mVoiceInteractionManagerService != null;
}
- // TODO(b/162600135): implement turning on/off visual interaction.
- }
- private final class TrustedDeviceDetectionPowerComponentMediator
- extends PowerComponentMediator {
- TrustedDeviceDetectionPowerComponentMediator() {
- super(PowerComponent.TRUSTED_DEVICE_DETECTION);
+ @Override
+ public void setEnabled(boolean enabled) {
+ try {
+ mVoiceInteractionManagerService.setDisabled(!enabled);
+ mIsEnabled = enabled;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "IVoiceInteractionManagerService.setDisabled(" + !enabled + ") failed",
+ e);
+ }
}
- // TODO(b/162600135): implement turning on/off trusted device detection.
- }
- private final class MicroPhonePowerComponentMediator extends PowerComponentMediator {
- MicroPhonePowerComponentMediator() {
- super(PowerComponent.MICROPHONE);
+ @Override
+ public boolean isEnabled() {
+ // IVoiceInteractionManagerService doesn't have a method to tell enabled state. Assuming
+ // voice interaction is controlled only by AAOS CPMS, it tracks the state internally.
+ // TODO(b/178504489): Add isEnabled to IVoiceInterctionManagerService and use it.
+ return mIsEnabled;
}
- // TODO(b/162600135): implement turning on/off microphone.
}
private final class PowerComponentMediatorFactory {
@@ -326,31 +309,35 @@
PowerComponentMediator createPowerComponent(int component) {
switch (component) {
case PowerComponent.AUDIO:
- return new PowerComponentHandler.AudioPowerComponentMediator();
+ // We don't control audio in framework level, because audio is enabled or
+ // disabled in audio HAL according to the current power policy.
+ return null;
case PowerComponent.MEDIA:
- return new MediaPowerComponentMediator();
+ return null;
case PowerComponent.DISPLAY:
return new DisplayPowerComponentMediator();
case PowerComponent.WIFI:
return new WifiPowerComponentMediator();
case PowerComponent.CELLULAR:
- return new CellularPowerComponentMediator();
+ return null;
case PowerComponent.ETHERNET:
- return new EthernetPowerComponentMediator();
+ return null;
case PowerComponent.PROJECTION:
- return new ProjectionPowerComponentMediator();
+ return null;
case PowerComponent.NFC:
- return new NfcPowerComponentMediator();
+ return null;
case PowerComponent.INPUT:
- return new InputPowerComponentMediator();
+ return null;
case PowerComponent.VOICE_INTERACTION:
return new VoiceInteractionPowerComponentMediator();
case PowerComponent.VISUAL_INTERACTION:
- return new VisualInteractionPowerComponentMediator();
+ return null;
case PowerComponent.TRUSTED_DEVICE_DETECTION:
- return new TrustedDeviceDetectionPowerComponentMediator();
+ return null;
case PowerComponent.MICROPHONE:
- return new MicroPhonePowerComponentMediator();
+ // We don't control microphone in framework level, because microphone is enabled
+ // or disabled in audio HAL according to the current power policy.
+ return null;
case PowerComponent.BLUETOOTH:
// com.android.car.BluetoothDeviceConnectionPolicy handles power state change.
// So, bluetooth mediator is not created.
@@ -359,6 +346,7 @@
// GNSS HAL handles power state change. So, location mediator is not created.
return null;
default:
+ Slog.w(TAG, "Unknown component(" + component + ")");
return null;
}
}
diff --git a/service/src/com/android/car/systeminterface/DisplayInterface.java b/service/src/com/android/car/systeminterface/DisplayInterface.java
index 3bd90c8..30bb304 100644
--- a/service/src/com/android/car/systeminterface/DisplayInterface.java
+++ b/service/src/com/android/car/systeminterface/DisplayInterface.java
@@ -50,14 +50,39 @@
*/
public interface DisplayInterface {
/**
+ * Sets display brightness.
+ *
* @param brightness Level from 0 to 100%
*/
void setDisplayBrightness(int brightness);
+
+ /**
+ * Turns on or off display.
+ *
+ * @param on {@code true} to turn on, {@code false} to turn off.
+ */
void setDisplayState(boolean on);
+
+ /**
+ * Starts monitoring the display state change.
+ *
+ * <p> When there is a change, {@link CarPowerManagementService} is notified.
+ *
+ * @param service {@link CarPowerManagementService} to listen to the change.
+ */
void startDisplayStateMonitoring(CarPowerManagementService service);
+
+ /**
+ * Stops monitoring the display state change.
+ */
void stopDisplayStateMonitoring();
/**
+ * Gets the current on/off state of display.
+ */
+ boolean isDisplayEnabled();
+
+ /**
* Refreshing display brightness. Used when user is switching and car turned on.
*/
void refreshDisplayBrightness();
@@ -244,6 +269,11 @@
}
}
+ @Override
+ public boolean isDisplayEnabled() {
+ return isMainDisplayOn();
+ }
+
private void onUsersUpdate() {
synchronized (mLock) {
if (mService == null) {
diff --git a/service/src/com/android/car/systeminterface/SystemInterface.java b/service/src/com/android/car/systeminterface/SystemInterface.java
index 928962d..8096946 100644
--- a/service/src/com/android/car/systeminterface/SystemInterface.java
+++ b/service/src/com/android/car/systeminterface/SystemInterface.java
@@ -147,6 +147,11 @@
}
@Override
+ public boolean isDisplayEnabled() {
+ return mDisplayInterface.isDisplayEnabled();
+ }
+
+ @Override
public WearInformationProvider[] getFlashWearInformationProviders() {
return mStorageMonitoringInterface.getFlashWearInformationProviders();
}
diff --git a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
index b444bbb..391a643 100644
--- a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
+++ b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
@@ -393,6 +393,11 @@
@Override
public void refreshDisplayBrightness() {}
+
+ @Override
+ public boolean isDisplayEnabled() {
+ return true;
+ }
}
static final class MockIOInterface implements IOInterface {
diff --git a/tests/carservice_test/src/com/android/car/power/CarPowerManagementTest.java b/tests/carservice_test/src/com/android/car/power/CarPowerManagementTest.java
index 228695a..bc2bdf8 100644
--- a/tests/carservice_test/src/com/android/car/power/CarPowerManagementTest.java
+++ b/tests/carservice_test/src/com/android/car/power/CarPowerManagementTest.java
@@ -359,6 +359,11 @@
@Override
public void refreshDisplayBrightness() {}
+
+ @Override
+ public boolean isDisplayEnabled() {
+ return mDisplayOn;
+ }
}
private class PowerStatePropertyHandler implements VehicleHalPropertyHandler {
diff --git a/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
index 0537e8c..4a07873 100644
--- a/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
@@ -53,6 +53,7 @@
import com.android.car.systeminterface.SystemInterface;
import com.android.car.systeminterface.SystemStateInterface;
import com.android.car.user.CarUserService;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IVoiceInteractionManagerService;
import org.junit.After;
@@ -407,6 +408,8 @@
}
private static final class MockDisplayInterface implements DisplayInterface {
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
private boolean mDisplayOn = true;
private final Semaphore mDisplayStateWait = new Semaphore(0);
@@ -414,18 +417,18 @@
public void setDisplayBrightness(int brightness) {}
@Override
- public synchronized void setDisplayState(boolean on) {
- mDisplayOn = on;
+ public void setDisplayState(boolean on) {
+ synchronized (mLock) {
+ mDisplayOn = on;
+ }
mDisplayStateWait.release();
}
- public synchronized boolean getDisplayState() {
- return mDisplayOn;
- }
-
public boolean waitForDisplayStateChange(long timeoutMs) throws Exception {
JavaMockitoHelper.await(mDisplayStateWait, timeoutMs);
- return mDisplayOn;
+ synchronized (mLock) {
+ return mDisplayOn;
+ }
}
@Override
@@ -436,6 +439,13 @@
@Override
public void refreshDisplayBrightness() {}
+
+ @Override
+ public boolean isDisplayEnabled() {
+ synchronized (mLock) {
+ return mDisplayOn;
+ }
+ }
}
/**
diff --git a/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
index dfbd685..3f18b01 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
@@ -66,6 +66,7 @@
import com.android.car.test.utils.TemporaryDirectory;
import com.android.car.test.utils.TemporaryFile;
import com.android.car.user.CarUserService;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.internal.os.IResultReceiver;
@@ -481,7 +482,7 @@
mPowerSignalListener.waitForSleepExit(WAIT_TIMEOUT_MS);
mService.scheduleNextWakeupTime(WAKE_UP_DELAY);
// second processing after wakeup
- assertThat(mDisplayInterface.getDisplayState()).isFalse();
+ assertThat(mDisplayInterface.isDisplayEnabled()).isFalse();
mService.setStateForTesting(/* isBooting= */ false);
@@ -507,7 +508,7 @@
// Since we just woke up from shutdown, wake up time will be 0
assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
assertVoiceInteractionEnabled();
- assertThat(mDisplayInterface.getDisplayState()).isFalse();
+ assertThat(mDisplayInterface.isDisplayEnabled()).isFalse();
}
private void assertStateReceived(int expectedState, int expectedParam) throws Exception {
@@ -579,6 +580,8 @@
}
private static final class MockDisplayInterface implements DisplayInterface {
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
private boolean mDisplayOn = true;
private final Semaphore mDisplayStateWait = new Semaphore(0);
@@ -586,15 +589,13 @@
public void setDisplayBrightness(int brightness) {}
@Override
- public synchronized void setDisplayState(boolean on) {
- mDisplayOn = on;
+ public void setDisplayState(boolean on) {
+ synchronized (mLock) {
+ mDisplayOn = on;
+ }
mDisplayStateWait.release();
}
- public synchronized boolean getDisplayState() {
- return mDisplayOn;
- }
-
private void waitForDisplayOn(long timeoutMs) throws Exception {
waitForDisplayState(true, timeoutMs);
}
@@ -605,7 +606,12 @@
private void waitForDisplayState(boolean desiredState, long timeoutMs) throws Exception {
int nTries = 0;
- while (mDisplayOn != desiredState) {
+ while (true) {
+ synchronized (mLock) {
+ if (mDisplayOn == desiredState) {
+ break;
+ }
+ }
if (nTries > 5) throw new IllegalStateException("timeout");
waitForSemaphore(mDisplayStateWait, timeoutMs);
nTries++;
@@ -620,6 +626,13 @@
@Override
public void refreshDisplayBrightness() {}
+
+ @Override
+ public boolean isDisplayEnabled() {
+ synchronized (mLock) {
+ return mDisplayOn;
+ }
+ }
}
private static final class MockSystemStateInterface implements SystemStateInterface {