Merge "Initial implementation of 'cmd voiceinteraction'." into rvc-dev am: edcb2c38f4

Change-Id: I63ae68c8d29701aa2587822c251f7a868577117e
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index ef282ba..cf07221 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -56,6 +56,8 @@
 import android.os.RemoteCallback;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
@@ -1391,6 +1393,13 @@
         }
 
         @Override
+        public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+                String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+            new VoiceInteractionManagerServiceShellCommand(mServiceStub)
+                    .exec(this, in, out, err, args, callback, resultReceiver);
+        }
+
+        @Override
         public void setUiHints(Bundle hints) {
             synchronized (this) {
                 enforceIsCurrentVoiceInteractionService();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
new file mode 100644
index 0000000..3f4ddb6
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
@@ -0,0 +1,135 @@
+/*
+ * 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.voiceinteraction;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.util.Slog;
+
+import com.android.internal.app.IVoiceInteractionSessionShowCallback;
+import com.android.server.voiceinteraction.VoiceInteractionManagerService.VoiceInteractionManagerServiceStub;
+
+import java.io.PrintWriter;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Shell command for {@link VoiceInteractionManagerService}.
+ */
+final class VoiceInteractionManagerServiceShellCommand extends ShellCommand {
+    private static final String TAG = "VoiceInteractionManager";
+    private static final long TIMEOUT_MS = 5_000;
+
+    private final VoiceInteractionManagerServiceStub mService;
+
+    VoiceInteractionManagerServiceShellCommand(VoiceInteractionManagerServiceStub service) {
+        mService = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        PrintWriter pw = getOutPrintWriter();
+        switch (cmd) {
+            case "show":
+                return requestShow(pw);
+            case "hide":
+                return requestHide(pw);
+            default:
+                return handleDefaultCommands(cmd);
+        }
+    }
+
+    @Override
+    public void onHelp() {
+        try (PrintWriter pw = getOutPrintWriter();) {
+            pw.println("VoiceInteraction Service (voiceinteraction) commands:");
+            pw.println("  help");
+            pw.println("    Prints this help text.");
+            pw.println("");
+            pw.println("  show");
+            pw.println("    Shows a session for the active service");
+            pw.println("");
+            pw.println("  hide");
+            pw.println("    Hides the current session");
+            pw.println("");
+        }
+    }
+
+    private int requestShow(PrintWriter pw) {
+        Slog.i(TAG, "requestShow()");
+        CountDownLatch latch = new CountDownLatch(1);
+        AtomicInteger result = new AtomicInteger();
+
+        IVoiceInteractionSessionShowCallback callback =
+                new IVoiceInteractionSessionShowCallback.Stub() {
+            @Override
+            public void onFailed() throws RemoteException {
+                Slog.w(TAG, "onFailed()");
+                pw.println("callback failed");
+                result.set(1);
+                latch.countDown();
+            }
+
+            @Override
+            public void onShown() throws RemoteException {
+                Slog.d(TAG, "onShown()");
+                result.set(0);
+                latch.countDown();
+            }
+        };
+
+        try {
+            Bundle args = new Bundle();
+            boolean ok = mService.showSessionForActiveService(args, /* sourceFlags= */ 0, callback,
+                    /* activityToken= */ null);
+
+            if (!ok) {
+                pw.println("showSessionForActiveService() returned false");
+                return 1;
+            }
+
+            if (!latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                pw.printf("Callback not called in %d ms\n", TIMEOUT_MS);
+                return 1;
+            }
+        } catch (Exception e) {
+            return handleError(pw, "showSessionForActiveService()", e);
+        }
+
+        return 0;
+    }
+
+    private int requestHide(PrintWriter pw) {
+        Slog.i(TAG, "requestHide()");
+        try {
+            mService.hideCurrentSession();
+        } catch (Exception e) {
+            return handleError(pw, "requestHide()", e);
+        }
+        return 0;
+    }
+
+    private static int handleError(PrintWriter pw, String message, Exception e) {
+        Slog.e(TAG,  "error calling " + message, e);
+        pw.printf("Error calling %s: %s\n", message, e);
+        return 1;
+    }
+}