diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java index b640e7f757b6f..af716242210ed 100755 --- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java @@ -91,7 +91,7 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction { private final DeviceDiscoveryCallback mCallback; private int mProcessedDeviceCount = 0; private int mTimeoutRetry = 0; - private boolean mIsTvDevice = source().mService.isTvDevice(); + private boolean mIsTvDevice = localDevice().mService.isTvDevice(); private final int mDelayPeriod; /** diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java index e777ce8166acf..86be585e5d23f 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecController.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java @@ -77,7 +77,7 @@ final class HdmiCecController { private static final int NUM_LOGICAL_ADDRESS = 16; - private static final int MAX_CEC_MESSAGE_HISTORY = 20; + private static final int MAX_CEC_MESSAGE_HISTORY = 200; // Predicate for whether the given logical address is remote device's one or not. private final Predicate mRemoteDeviceAddressPredicate = new Predicate() { @@ -682,7 +682,7 @@ final class HdmiCecController { void dump(final IndentingPrintWriter pw) { for (int i = 0; i < mLocalDevices.size(); ++i) { - pw.println("HdmiCecLocalDevice #" + i + ":"); + pw.println("HdmiCecLocalDevice #" + mLocalDevices.keyAt(i) + ":"); pw.increaseIndent(); mLocalDevices.valueAt(i).dump(pw); pw.decreaseIndent(); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index cd0653f164e96..5c1b3deb99556 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -37,6 +37,7 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.hdmi.Constants.AudioCodec; import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; @@ -89,12 +90,10 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); - mSystemAudioControlFeatureEnabled = true; - // TODO(amyjojo) make System Audio Control controllable by users - /*mSystemAudioControlFeatureEnabled = - mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);*/ mRoutingControlFeatureEnabled = mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, true); + mSystemAudioControlFeatureEnabled = + mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true); // TODO(amyjojo): make the map ro property. mTvInputs.put(Constants.CEC_SWITCH_HDMI1, "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5"); @@ -275,7 +274,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { int systemAudioOnPowerOnProp, boolean lastSystemAudioControlStatus) { if ((systemAudioOnPowerOnProp == ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON) || ((systemAudioOnPowerOnProp == USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON) - && lastSystemAudioControlStatus)) { + && lastSystemAudioControlStatus && isSystemAudioControlFeatureEnabled())) { addAndStartAction(new SystemAudioInitiationActionFromAvr(this)); } } @@ -408,8 +407,11 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { @ServiceThreadOnly protected boolean handleGiveAudioStatus(HdmiCecMessage message) { assertRunOnServiceThread(); - - reportAudioStatus(message.getSource()); + if (isSystemAudioControlFeatureEnabled()) { + reportAudioStatus(message.getSource()); + } else { + mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); + } return true; } @@ -776,6 +778,13 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device); } + void onSystemAduioControlFeatureSupportChanged(boolean enabled) { + setSystemAudioControlFeatureEnabled(enabled); + if (enabled) { + addAndStartAction(new SystemAudioInitiationActionFromAvr(this)); + } + } + @ServiceThreadOnly void setSystemAudioControlFeatureEnabled(boolean enabled) { assertRunOnServiceThread(); @@ -1078,4 +1087,20 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { } mDeviceInfos.clear(); } + + @Override + protected void dump(IndentingPrintWriter pw) { + pw.println("HdmiCecLocalDeviceAudioSystem:"); + pw.increaseIndent(); + pw.println("mSystemAudioActivated: " + mSystemAudioActivated); + pw.println("mSystemAudioControlFeatureEnabled: " + mSystemAudioControlFeatureEnabled); + pw.println("mTvSystemAudioModeSupport: " + mTvSystemAudioModeSupport); + pw.println("mArcEstablished: " + mArcEstablished); + pw.println("mArcIntentUsed: " + mArcIntentUsed); + HdmiUtils.dumpMap(pw, "mTvInputs:", mTvInputs); + HdmiUtils.dumpSparseArray(pw, "mDeviceInfos:", mDeviceInfos); + pw.decreaseIndent(); + super.dump(pw); + } + } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java index 4052c8a87c4e4..f8b39627f2360 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java @@ -112,12 +112,11 @@ public final class HdmiCecMessage { @Override public String toString() { StringBuffer s = new StringBuffer(); - s.append(String.format("<%s> src: %d, dst: %d", - opcodeToString(mOpcode), mSource, mDestination)); + s.append(String.format("<%s> %X%X:%02X", + opcodeToString(mOpcode), mSource, mDestination, mOpcode)); if (mParams.length > 0) { - s.append(", params:"); for (byte data : mParams) { - s.append(String.format(" %02X", data)); + s.append(String.format(":%02X", data)); } } return s.toString(); diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index fcfb0664ea957..aabe1ad659d6a 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -26,6 +26,7 @@ import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE; import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING; import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE; import static com.android.server.hdmi.Constants.OPTION_MHL_SERVICE_CONTROL; +import static com.android.server.power.ShutdownThread.SHUTDOWN_ACTION_PROPERTY; import android.annotation.Nullable; import android.content.BroadcastReceiver; @@ -184,9 +185,10 @@ public class HdmiControlService extends SystemService { @Override public void onReceive(Context context, Intent intent) { assertRunOnServiceThread(); + boolean isReboot = SystemProperties.get(SHUTDOWN_ACTION_PROPERTY).contains("1"); switch (intent.getAction()) { case Intent.ACTION_SCREEN_OFF: - if (isPowerOnOrTransient()) { + if (isPowerOnOrTransient() && !isReboot) { onStandby(STANDBY_SCREEN_OFF); } break; @@ -202,7 +204,7 @@ public class HdmiControlService extends SystemService { } break; case Intent.ACTION_SHUTDOWN: - if (isPowerOnOrTransient()) { + if (isPowerOnOrTransient() && !isReboot) { onStandby(STANDBY_SHUTDOWN); } break; @@ -610,6 +612,9 @@ public class HdmiControlService extends SystemService { if (isTvDeviceEnabled()) { tv().setSystemAudioControlFeatureEnabled(enabled); } + if (isAudioSystemDevice()) { + audioSystem().onSystemAduioControlFeatureSupportChanged(enabled); + } break; case Global.HDMI_CEC_SWITCH_ENABLED: if (isAudioSystemDevice()) { @@ -1887,27 +1892,28 @@ public class HdmiControlService extends SystemService { if (!DumpUtils.checkDumpPermission(getContext(), TAG, writer)) return; final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); - pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled); pw.println("mProhibitMode: " + mProhibitMode); - if (mCecController != null) { - pw.println("mCecController: "); - pw.increaseIndent(); - mCecController.dump(pw); - pw.decreaseIndent(); - } + pw.println("mPowerStatus: " + mPowerStatus); + + // System settings + pw.println("System_settings:"); + pw.increaseIndent(); + pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled); + pw.println("mMhlInputChangeEnabled: " + mMhlInputChangeEnabled); + pw.decreaseIndent(); pw.println("mMhlController: "); pw.increaseIndent(); mMhlController.dump(pw); pw.decreaseIndent(); - pw.println("mPortInfo: "); - pw.increaseIndent(); - for (HdmiPortInfo hdmiPortInfo : mPortInfo) { - pw.println("- " + hdmiPortInfo); + HdmiUtils.dumpIterable(pw, "mPortInfo:", mPortInfo); + if (mCecController != null) { + pw.println("mCecController: "); + pw.increaseIndent(); + mCecController.dump(pw); + pw.decreaseIndent(); } - pw.decreaseIndent(); - pw.println("mPowerStatus: " + mPowerStatus); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java index 2a8117fac68da..21106828d43f6 100644 --- a/services/core/java/com/android/server/hdmi/HdmiUtils.java +++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java @@ -20,9 +20,13 @@ import android.hardware.hdmi.HdmiDeviceInfo; import android.util.Slog; import android.util.SparseArray; +import com.android.internal.util.IndentingPrintWriter; + import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; + /** * Various utilities to handle HDMI CEC messages. @@ -317,4 +321,74 @@ final class HdmiUtils { info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(), info.getVendorId(), info.getDisplayName(), newPowerStatus); } + + /** + * Dump a {@link SparseArray} to the print writer. + * + *

The dump is formatted: + *

+     *     name:
+     *        key = value
+     *        key = value
+     *        ...
+     * 
+ */ + static void dumpSparseArray(IndentingPrintWriter pw, String name, + SparseArray sparseArray) { + printWithTrailingColon(pw, name); + pw.increaseIndent(); + int size = sparseArray.size(); + for (int i = 0; i < size; i++) { + int key = sparseArray.keyAt(i); + T value = sparseArray.get(key); + pw.printPair(Integer.toString(key), value); + pw.println(); + } + pw.decreaseIndent(); + } + + private static void printWithTrailingColon(IndentingPrintWriter pw, String name) { + pw.println(name.endsWith(":") ? name : name.concat(":")); + } + + /** + * Dump a {@link Map} to the print writer. + * + *

The dump is formatted: + *

+     *     name:
+     *        key = value
+     *        key = value
+     *        ...
+     * 
+ */ + static void dumpMap(IndentingPrintWriter pw, String name, Map map) { + printWithTrailingColon(pw, name); + pw.increaseIndent(); + for (Map.Entry entry: map.entrySet()) { + pw.printPair(entry.getKey().toString(), entry.getValue()); + pw.println(); + } + pw.decreaseIndent(); + } + + /** + * Dump a {@link Map} to the print writer. + * + *

The dump is formatted: + *

+     *     name:
+     *        value
+     *        value
+     *        ...
+     * 
+ */ + static void dumpIterable(IndentingPrintWriter pw, String name, Iterable values) { + printWithTrailingColon(pw, name); + pw.increaseIndent(); + for (T value : values) { + pw.println(value); + } + pw.decreaseIndent(); + } }