summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--core/java/android/hardware/hdmi/IHdmiControlService.aidl6
-rw-r--r--core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl31
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java21
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java124
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioAction.java32
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java10
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java6
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java4
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java25
10 files changed, 239 insertions, 21 deletions
diff --git a/Android.mk b/Android.mk
index 8f7779ea2c32..936b41a38c86 100644
--- a/Android.mk
+++ b/Android.mk
@@ -152,6 +152,7 @@ LOCAL_SRC_FILES += \
core/java/android/hardware/hdmi/IHdmiControlService.aidl \
core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl \
core/java/android/hardware/hdmi/IHdmiHotplugEventListener.aidl \
+ core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl \
core/java/android/hardware/input/IInputManager.aidl \
core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
core/java/android/hardware/location/IFusedLocationHardware.aidl \
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 559a469e5269..73726fa49843 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -21,6 +21,7 @@ import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiDeviceEventListener;
import android.hardware.hdmi.IHdmiHotplugEventListener;
+import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
import java.util.List;
@@ -42,4 +43,9 @@ interface IHdmiControlService {
void portSelect(int portId, IHdmiControlCallback callback);
void sendKeyEvent(int keyCode, boolean isPressed);
List<HdmiPortInfo> getPortInfo();
+ boolean canChangeSystemAudioMode();
+ boolean getSystemAudioMode();
+ void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback);
+ void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
+ void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
}
diff --git a/core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl b/core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl
new file mode 100644
index 000000000000..714bbe720ae7
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 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.hardware.hdmi;
+
+/**
+ * Callback interface definition for HDMI client to get informed of
+ * "System Audio" mode change.
+ *
+ * @hide
+ */
+oneway interface IHdmiSystemAudioModeChangeListener {
+
+ /**
+ * @param enabled true if the device gets activated
+ */
+ void onStatusChanged(in boolean enabled);
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 52c092cd7e05..1210e1029410 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -253,20 +253,35 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
mDeviceInfos.clear();
}
+ void changeSystemAudioMode(boolean enabled, IHdmiControlCallback callback) {
+ assertRunOnServiceThread();
+ HdmiCecDeviceInfo avr = getAvrDeviceInfo();
+ if (avr == null) {
+ invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
+ return;
+ }
+
+ addAndStartAction(
+ new SystemAudioActionFromTv(this, avr.getLogicalAddress(), enabled, callback));
+ }
+
+ boolean canChangeSystemAudioMode() {
+ // TODO: once have immutable device info, test whether avr info exists or not.
+ return false;
+ }
+
void setSystemAudioMode(boolean on) {
synchronized (mLock) {
if (on != mSystemAudioMode) {
mSystemAudioMode = on;
// TODO: Need to set the preference for SystemAudioMode.
- // TODO: Need to handle the notification of changing the mode and
- // to identify the notification should be handled in the service or TvSettings.
+ mService.announceSystemAudioModeChange(on);
}
}
}
boolean getSystemAudioMode() {
synchronized (mLock) {
- assertRunOnServiceThread();
return mSystemAudioMode;
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index d323f34ed101..77748786f483 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -27,6 +27,7 @@ import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiControlService;
import android.hardware.hdmi.IHdmiDeviceEventListener;
import android.hardware.hdmi.IHdmiHotplugEventListener;
+import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
@@ -113,6 +114,14 @@ public final class HdmiControlService extends SystemService {
private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords =
new ArrayList<>();
+ // List of listeners registered by callers that want to get notified of
+ // system audio mode changes.
+ private final ArrayList<IHdmiSystemAudioModeChangeListener>
+ mSystemAudioModeChangeListeners = new ArrayList<>();
+ // List of records for system audio mode change to handle the the caller killed in action.
+ private final ArrayList<SystemAudioModeChangeListenerRecord>
+ mSystemAudioModeChangeListenerRecords = new ArrayList<>();
+
// Handler used to run a task in service thread.
private final Handler mHandler = new Handler();
@@ -447,6 +456,12 @@ public final class HdmiControlService extends SystemService {
// TODO: Hook up with AudioManager.
}
+ void announceSystemAudioModeChange(boolean enabled) {
+ for (IHdmiSystemAudioModeChangeListener listener : mSystemAudioModeChangeListeners) {
+ invokeSystemAudioModeChange(listener, enabled);
+ }
+ }
+
private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) {
// TODO: find better name instead of model name.
String displayName = Build.MODEL;
@@ -480,7 +495,7 @@ public final class HdmiControlService extends SystemService {
}
@Override
- public void binderDied() {
+ public void binderDied() {
synchronized (mLock) {
mDeviceEventListenerRecords.remove(this);
mDeviceEventListeners.remove(mListener);
@@ -488,6 +503,22 @@ public final class HdmiControlService extends SystemService {
}
}
+ private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient {
+ private IHdmiSystemAudioModeChangeListener mListener;
+
+ public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ mSystemAudioModeChangeListenerRecords.remove(this);
+ mSystemAudioModeChangeListeners.remove(mListener);
+ }
+ }
+ }
+
private void enforceAccessPermission() {
getContext().enforceCallingOrSelfPermission(PERMISSION, TAG);
}
@@ -605,7 +636,7 @@ public final class HdmiControlService extends SystemService {
enforceAccessPermission();
runOnServiceThread(new Runnable() {
@Override
- public void run() {
+ public void run() {
HdmiControlService.this.addDeviceEventListener(listener);
}
});
@@ -616,6 +647,57 @@ public final class HdmiControlService extends SystemService {
enforceAccessPermission();
return mPortInfo;
}
+
+ @Override
+ public boolean canChangeSystemAudioMode() {
+ enforceAccessPermission();
+ HdmiCecLocalDeviceTv tv = tv();
+ if (tv == null) {
+ return false;
+ }
+ return tv.canChangeSystemAudioMode();
+ }
+
+ @Override
+ public boolean getSystemAudioMode() {
+ enforceAccessPermission();
+ HdmiCecLocalDeviceTv tv = tv();
+ if (tv == null) {
+ return false;
+ }
+ return tv.getSystemAudioMode();
+ }
+
+ @Override
+ public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) {
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ HdmiCecLocalDeviceTv tv = tv();
+ if (tv == null) {
+ Slog.w(TAG, "Local tv device not available");
+ invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
+ return;
+ }
+ tv.changeSystemAudioMode(enabled, callback);
+ }
+ });
+ }
+
+ @Override
+ public void addSystemAudioModeChangeListener(
+ final IHdmiSystemAudioModeChangeListener listener) {
+ enforceAccessPermission();
+ HdmiControlService.this.addSystemAudioModeChangeListner(listener);
+ }
+
+ @Override
+ public void removeSystemAudioModeChangeListener(
+ final IHdmiSystemAudioModeChangeListener listener) {
+ enforceAccessPermission();
+ HdmiControlService.this.removeSystemAudioModeChangeListener(listener);
+ }
}
private void oneTouchPlay(final IHdmiControlCallback callback) {
@@ -693,6 +775,35 @@ public final class HdmiControlService extends SystemService {
}
}
+ private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) {
+ SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord(
+ listener);
+ try {
+ listener.asBinder().linkToDeath(record, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Listener already died");
+ return;
+ }
+ synchronized (mLock) {
+ mSystemAudioModeChangeListeners.add(listener);
+ mSystemAudioModeChangeListenerRecords.add(record);
+ }
+ }
+
+ private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) {
+ synchronized (mLock) {
+ for (SystemAudioModeChangeListenerRecord record :
+ mSystemAudioModeChangeListenerRecords) {
+ if (record.mListener.asBinder() == listener) {
+ listener.asBinder().unlinkToDeath(record, 0);
+ mSystemAudioModeChangeListenerRecords.remove(record);
+ break;
+ }
+ }
+ mSystemAudioModeChangeListeners.remove(listener);
+ }
+ }
+
private void invokeCallback(IHdmiControlCallback callback, int result) {
try {
callback.onComplete(result);
@@ -701,6 +812,15 @@ public final class HdmiControlService extends SystemService {
}
}
+ private void invokeSystemAudioModeChange(IHdmiSystemAudioModeChangeListener listener,
+ boolean enabled) {
+ try {
+ listener.onStatusChanged(enabled);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Invoking callback failed:" + e);
+ }
+ }
+
private void announceHotplugEvent(int portId, boolean connected) {
HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected);
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index 92418abf6d5f..959a38e83ee9 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -16,8 +16,12 @@
package com.android.server.hdmi;
+import android.annotation.Nullable;
import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.RemoteException;
+import android.util.Slog;
/**
* Base feature action class for SystemAudioActionFromTv and SystemAudioActionFromAvr.
@@ -39,6 +43,8 @@ abstract class SystemAudioAction extends FeatureAction {
// The target audio status of the action, whether to enable the system audio mode or not.
protected boolean mTargetAudioStatus;
+ @Nullable private final IHdmiControlCallback mCallback;
+
private int mSendRetryCount = 0;
/**
@@ -47,13 +53,16 @@ abstract class SystemAudioAction extends FeatureAction {
* @param source {@link HdmiCecLocalDevice} instance
* @param avrAddress logical address of AVR device
* @param targetStatus Whether to enable the system audio mode or not
+ * @param callback callback interface to be notified when it's done
* @throw IllegalArugmentException if device type of sourceAddress and avrAddress is invalid
*/
- SystemAudioAction(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus) {
+ SystemAudioAction(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus,
+ IHdmiControlCallback callback) {
super(source);
HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
mAvrLogicalAddress = avrAddress;
mTargetAudioStatus = targetStatus;
+ mCallback = callback;
}
protected void sendSystemAudioModeRequest() {
@@ -69,7 +78,7 @@ abstract class SystemAudioAction extends FeatureAction {
addTimer(mState, mTargetAudioStatus ? ON_TIMEOUT_MS : OFF_TIMEOUT_MS);
} else {
setSystemAudioMode(false);
- finish();
+ finishWithCallback(HdmiCec.RESULT_EXCEPTION);
}
}
});
@@ -79,7 +88,7 @@ abstract class SystemAudioAction extends FeatureAction {
if (!mTargetAudioStatus // Don't retry for Off case.
|| mSendRetryCount++ >= MAX_SEND_RETRY_COUNT) {
setSystemAudioMode(false);
- finish();
+ finishWithCallback(HdmiCec.RESULT_TIMEOUT);
return;
}
sendSystemAudioModeRequest();
@@ -107,7 +116,7 @@ abstract class SystemAudioAction extends FeatureAction {
// Unexpected response, consider the request is newly initiated by AVR.
// To return 'false' will initiate new SystemAudioActionFromAvr by the control
// service.
- finish();
+ finishWithCallback(HdmiCec.RESULT_EXCEPTION);
return false;
}
default:
@@ -116,7 +125,7 @@ abstract class SystemAudioAction extends FeatureAction {
}
protected void startAudioStatusAction() {
- addAndStartAction(new SystemAudioStatusAction(tv(), mAvrLogicalAddress));
+ addAndStartAction(new SystemAudioStatusAction(tv(), mAvrLogicalAddress, mCallback));
finish();
}
@@ -136,4 +145,17 @@ abstract class SystemAudioAction extends FeatureAction {
return;
}
}
+
+ // TODO: if IHdmiControlCallback is general to other FeatureAction,
+ // move it into FeatureAction.
+ protected void finishWithCallback(int returnCode) {
+ if (mCallback != null) {
+ try {
+ mCallback.onComplete(returnCode);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to invoke callback.", e);
+ }
+ }
+ finish();
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
index b743c64571b9..9d345897bf7b 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
@@ -17,6 +17,7 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.IHdmiControlCallback;
/**
* Feature action that handles System Audio initiated by AVR devices.
@@ -28,11 +29,12 @@ final class SystemAudioActionFromAvr extends SystemAudioAction {
* @param source {@link HdmiCecLocalDevice} instance
* @param avrAddress logical address of AVR device
* @param targetStatus Whether to enable the system audio mode or not
+ * @param callback callback interface to be notified when it's done
* @throw IllegalArugmentException if device type of tvAddress and avrAddress is invalid
*/
SystemAudioActionFromAvr(HdmiCecLocalDevice source, int avrAddress,
- boolean targetStatus) {
- super(source, avrAddress, targetStatus);
+ boolean targetStatus, IHdmiControlCallback callback) {
+ super(source, avrAddress, targetStatus, callback);
HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV);
}
@@ -45,7 +47,7 @@ final class SystemAudioActionFromAvr extends SystemAudioAction {
private void handleSystemAudioActionFromAvr() {
if (mTargetAudioStatus == tv().getSystemAudioMode()) {
- finish();
+ finishWithCallback(HdmiCec.RESULT_SUCCESS);
return;
}
if (tv().isInPresetInstallationMode()) {
@@ -62,7 +64,7 @@ final class SystemAudioActionFromAvr extends SystemAudioAction {
startAudioStatusAction();
} else {
setSystemAudioMode(false);
- finish();
+ finishWithCallback(HdmiCec.RESULT_SUCCESS);
}
}
}
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
index e0c4ff47a2f7..2d8f3fcc832d 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
@@ -17,6 +17,7 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.IHdmiControlCallback;
/**
@@ -29,11 +30,12 @@ final class SystemAudioActionFromTv extends SystemAudioAction {
* @param sourceAddress {@link HdmiCecLocalDevice} instance
* @param avrAddress logical address of AVR device
* @param targetStatus Whether to enable the system audio mode or not
+ * @param callback callback interface to be notified when it's done
* @throw IllegalArugmentException if device type of tvAddress is invalid
*/
SystemAudioActionFromTv(HdmiCecLocalDevice sourceAddress, int avrAddress,
- boolean targetStatus) {
- super(sourceAddress, avrAddress, targetStatus);
+ boolean targetStatus, IHdmiControlCallback callback) {
+ super(sourceAddress, avrAddress, targetStatus, callback);
HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV);
}
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
index e4d82ef88eaa..c7ab406f7207 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -77,14 +77,14 @@ final class SystemAudioAutoInitiationAction extends FeatureAction {
// If the last setting is system audio, turn on system audio whatever AVR status is.
if (tv().getSystemAudioMode()) {
if (canChangeSystemAudio()) {
- addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress, true));
+ addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress, true, null));
}
} else {
// If the last setting is non-system audio, turn off system audio mode
// and update system audio status (volume or mute).
tv().setSystemAudioMode(false);
if (canChangeSystemAudio()) {
- addAndStartAction(new SystemAudioStatusAction(tv(), mAvrAddress));
+ addAndStartAction(new SystemAudioStatusAction(tv(), mAvrAddress, null));
}
}
finish();
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index 5f4fc23dfe03..89206a71abb0 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -16,8 +16,11 @@
package com.android.server.hdmi;
+import android.annotation.Nullable;
import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.RemoteException;
import android.util.Slog;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
@@ -32,10 +35,13 @@ final class SystemAudioStatusAction extends FeatureAction {
private static final int STATE_WAIT_FOR_REPORT_AUDIO_STATUS = 1;
private final int mAvrAddress;
+ @Nullable private final IHdmiControlCallback mCallback;
- SystemAudioStatusAction(HdmiCecLocalDevice source, int avrAddress) {
+ SystemAudioStatusAction(HdmiCecLocalDevice source, int avrAddress,
+ IHdmiControlCallback callback) {
super(source);
mAvrAddress = avrAddress;
+ mCallback = callback;
}
@Override
@@ -67,7 +73,9 @@ final class SystemAudioStatusAction extends FeatureAction {
? HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION // SystemAudioMode: ON
: HdmiConstants.UI_COMMAND_MUTE_FUNCTION; // SystemAudioMode: OFF
sendUserControlPressedAndReleased(uiCommand);
- finish();
+
+ // Still return SUCCESS to callback.
+ finishWithCallback(HdmiCec.RESULT_SUCCESS);
}
private void sendUserControlPressedAndReleased(int uiCommand) {
@@ -103,7 +111,7 @@ final class SystemAudioStatusAction extends FeatureAction {
// Toggle AVR's mute status to match with the system audio status.
sendUserControlPressedAndReleased(HdmiConstants.UI_COMMAND_MUTE);
}
- finish();
+ finishWithCallback(HdmiCec.RESULT_SUCCESS);
} else {
Slog.e(TAG, "Invalid <Report Audio Status> message:" + cmd);
handleSendGiveAudioStatusFailure();
@@ -111,6 +119,17 @@ final class SystemAudioStatusAction extends FeatureAction {
}
}
+ private void finishWithCallback(int returnCode) {
+ if (mCallback != null) {
+ try {
+ mCallback.onComplete(returnCode);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to invoke callback.", e);
+ }
+ }
+ finish();
+ }
+
@Override
void handleTimerEvent(int state) {
if (mState != state) {