1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server.voiceinteraction; 17 18 import android.os.Bundle; 19 import android.os.RemoteException; 20 import android.os.ShellCommand; 21 import android.util.Slog; 22 23 import com.android.internal.app.IVoiceInteractionSessionShowCallback; 24 import com.android.server.voiceinteraction.VoiceInteractionManagerService.VoiceInteractionManagerServiceStub; 25 26 import java.io.PrintWriter; 27 import java.util.concurrent.CountDownLatch; 28 import java.util.concurrent.TimeUnit; 29 import java.util.concurrent.atomic.AtomicInteger; 30 31 /** 32 * Shell command for {@link VoiceInteractionManagerService}. 33 */ 34 final class VoiceInteractionManagerServiceShellCommand extends ShellCommand { 35 private static final String TAG = "VoiceInteractionManager"; 36 private static final long TIMEOUT_MS = 5_000; 37 38 private final VoiceInteractionManagerServiceStub mService; 39 VoiceInteractionManagerServiceShellCommand(VoiceInteractionManagerServiceStub service)40 VoiceInteractionManagerServiceShellCommand(VoiceInteractionManagerServiceStub service) { 41 mService = service; 42 } 43 44 @Override onCommand(String cmd)45 public int onCommand(String cmd) { 46 if (cmd == null) { 47 return handleDefaultCommands(cmd); 48 } 49 PrintWriter pw = getOutPrintWriter(); 50 switch (cmd) { 51 case "show": 52 return requestShow(pw); 53 case "hide": 54 return requestHide(pw); 55 case "disable": 56 return requestDisable(pw); 57 case "restart-detection": 58 return requestRestartDetection(pw); 59 case "set-debug-hotword-logging": 60 return setDebugHotwordLogging(pw); 61 default: 62 return handleDefaultCommands(cmd); 63 } 64 } 65 66 @Override onHelp()67 public void onHelp() { 68 try (PrintWriter pw = getOutPrintWriter();) { 69 pw.println("VoiceInteraction Service (voiceinteraction) commands:"); 70 pw.println(" help"); 71 pw.println(" Prints this help text."); 72 pw.println(""); 73 pw.println(" show"); 74 pw.println(" Shows a session for the active service"); 75 pw.println(""); 76 pw.println(" hide"); 77 pw.println(" Hides the current session"); 78 pw.println(""); 79 pw.println(" disable [true|false]"); 80 pw.println(" Temporarily disable (when true) service"); 81 pw.println(""); 82 pw.println(" restart-detection"); 83 pw.println(" Force a restart of a hotword detection service"); 84 pw.println(""); 85 pw.println(" set-debug-hotword-logging [true|false]"); 86 pw.println(" Temporarily enable or disable debug logging for hotword result."); 87 pw.println(" The debug logging will be reset after one hour from last enable."); 88 pw.println(""); 89 } 90 } 91 requestShow(PrintWriter pw)92 private int requestShow(PrintWriter pw) { 93 Slog.i(TAG, "requestShow()"); 94 CountDownLatch latch = new CountDownLatch(1); 95 AtomicInteger result = new AtomicInteger(); 96 97 IVoiceInteractionSessionShowCallback callback = 98 new IVoiceInteractionSessionShowCallback.Stub() { 99 @Override 100 public void onFailed() throws RemoteException { 101 Slog.w(TAG, "onFailed()"); 102 pw.println("callback failed"); 103 result.set(1); 104 latch.countDown(); 105 } 106 107 @Override 108 public void onShown() throws RemoteException { 109 Slog.d(TAG, "onShown()"); 110 result.set(0); 111 latch.countDown(); 112 } 113 }; 114 115 try { 116 Bundle args = new Bundle(); 117 boolean ok = mService.showSessionForActiveService(args, /* sourceFlags= */ 0, callback, 118 /* activityToken= */ null); 119 120 if (!ok) { 121 pw.println("showSessionForActiveService() returned false"); 122 return 1; 123 } 124 125 if (!latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 126 pw.printf("Callback not called in %d ms\n", TIMEOUT_MS); 127 return 1; 128 } 129 } catch (Exception e) { 130 return handleError(pw, "showSessionForActiveService()", e); 131 } 132 133 return 0; 134 } 135 requestHide(PrintWriter pw)136 private int requestHide(PrintWriter pw) { 137 Slog.i(TAG, "requestHide()"); 138 try { 139 mService.hideCurrentSession(); 140 } catch (Exception e) { 141 return handleError(pw, "requestHide()", e); 142 } 143 return 0; 144 } 145 requestDisable(PrintWriter pw)146 private int requestDisable(PrintWriter pw) { 147 boolean disabled = Boolean.parseBoolean(getNextArgRequired()); 148 Slog.i(TAG, "requestDisable(): " + disabled); 149 try { 150 mService.setDisabled(disabled); 151 } catch (Exception e) { 152 return handleError(pw, "requestDisable()", e); 153 } 154 return 0; 155 } 156 requestRestartDetection(PrintWriter pw)157 private int requestRestartDetection(PrintWriter pw) { 158 Slog.i(TAG, "requestRestartDetection()"); 159 try { 160 mService.forceRestartHotwordDetector(); 161 } catch (Exception e) { 162 return handleError(pw, "requestRestartDetection()", e); 163 } 164 return 0; 165 } 166 setDebugHotwordLogging(PrintWriter pw)167 private int setDebugHotwordLogging(PrintWriter pw) { 168 boolean logging = Boolean.parseBoolean(getNextArgRequired()); 169 Slog.i(TAG, "setDebugHotwordLogging(): " + logging); 170 try { 171 mService.setDebugHotwordLogging(logging); 172 } catch (Exception e) { 173 return handleError(pw, "setDebugHotwordLogging()", e); 174 } 175 return 0; 176 } 177 handleError(PrintWriter pw, String message, Exception e)178 private static int handleError(PrintWriter pw, String message, Exception e) { 179 Slog.e(TAG, "error calling " + message, e); 180 pw.printf("Error calling %s: %s\n", message, e); 181 return 1; 182 } 183 } 184