Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b53652d authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes Ie19ab056,Ie9b71083

* changes:
  Implement adb command to send vendor commands
  Implement ADB command for OTP
parents b3db690a 760cefe4
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -66,6 +66,8 @@ import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -2290,6 +2292,16 @@ public class HdmiControlService extends SystemService {
            });
        }

        @Override
        public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
                @Nullable FileDescriptor err, String[] args,
                @Nullable ShellCallback callback, ResultReceiver resultReceiver)
                throws RemoteException {
            enforceAccessPermission();
            new HdmiControlShellCommand(this)
                    .exec(this, in, out, err, args, callback, resultReceiver);
        }

        @Override
        protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
            if (!DumpUtils.checkDumpPermission(getContext(), TAG, writer)) return;
+160 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 com.android.server.hdmi;


import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiControlService;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.util.Slog;

import java.io.PrintWriter;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

final class HdmiControlShellCommand extends ShellCommand {

    private static final String TAG = "HdmiShellCommand";

    private final IHdmiControlService.Stub mBinderService;


    HdmiControlShellCommand(IHdmiControlService.Stub binderService) {
        mBinderService = binderService;
    }

    @Override
    public int onCommand(String cmd) {
        if (cmd == null) {
            return handleDefaultCommands(cmd);
        }

        try {
            return handleShellCommand(cmd);
        } catch (Exception e) {
            getErrPrintWriter().println(
                    "Caught error for command '" + cmd + "': " + e.getMessage());
            Slog.e(TAG, "Error handling hdmi_control shell command: " + cmd, e);
            return 1;
        }
    }

    @Override
    public void onHelp() {
        PrintWriter pw = getOutPrintWriter();

        pw.println("HdmiControlManager (hdmi_control) commands:");
        pw.println("  help");
        pw.println("      Print this help text.");
        pw.println("  onetouchplay, otp");
        pw.println("      Send the \"One Touch Play\" feature from a source to the TV");
        pw.println("  vendorcommand --device_type <originating device type>");
        pw.println("                --destination <destination device>");
        pw.println("                --args <vendor specific arguments>");
        pw.println("                [--id <true if vendor command should be sent with vendor id>]");
        pw.println("      Send a Vendor Command to the given target device");
    }

    private int handleShellCommand(String cmd) throws RemoteException {
        PrintWriter pw = getOutPrintWriter();

        switch (cmd) {
            case "otp":
            case "onetouchplay":
                return oneTouchPlay(pw);
            case "vendorcommand":
                return vendorCommand(pw);
        }

        getErrPrintWriter().println("Unhandled command: " + cmd);
        return 1;
    }

    private int oneTouchPlay(PrintWriter pw) throws RemoteException {
        final CountDownLatch latch = new CountDownLatch(1);
        AtomicInteger cecResult = new AtomicInteger();
        pw.print("Sending One Touch Play...");
        mBinderService.oneTouchPlay(new IHdmiControlCallback.Stub() {
            @Override
            public void onComplete(int result) {
                pw.println(" done (" + result + ")");
                latch.countDown();
                cecResult.set(result);
            }
        });

        try {
            if (!latch.await(HdmiConfig.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
                getErrPrintWriter().println("One Touch Play timed out.");
                return 1;
            }
        } catch (InterruptedException e) {
            getErrPrintWriter().println("Caught InterruptedException");
            Thread.currentThread().interrupt();
        }
        return cecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1;
    }

    private int vendorCommand(PrintWriter pw) throws RemoteException {
        if (6 > getRemainingArgsCount()) {
            throw new IllegalArgumentException("Expected 3 arguments.");
        }

        int deviceType = -1;
        int destination = -1;
        String parameters = "";
        boolean hasVendorId = false;

        String arg = getNextOption();
        while (arg != null) {
            switch (arg) {
                case "-t":
                case "--device_type":
                    deviceType = Integer.parseInt(getNextArgRequired());
                    break;
                case "-d":
                case "--destination":
                    destination = Integer.parseInt(getNextArgRequired());
                    break;
                case "-a":
                case "--args":
                    parameters = getNextArgRequired();
                    break;
                case "-i":
                case "--id":
                    hasVendorId = Boolean.parseBoolean(getNextArgRequired());
                    break;
                default:
                    throw new IllegalArgumentException("Unknown argument: " + arg);
            }
            arg = getNextArg();
        }

        String[] parts = parameters.split(":");
        byte[] params = new byte[parts.length];
        for (int i = 0; i < params.length; i++) {
            params[i] = (byte) Integer.parseInt(parts[i], 16);
        }

        pw.println("Sending <Vendor Command>");
        mBinderService.sendVendorCommand(deviceType, destination, params, hasVendorId);
        return 0;
    }
}