Home | History | Annotate | Download | only in service
      1 /*
      2  * Copyright (C) 2015 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 
     17 package android.voiceinteraction.service;
     18 
     19 import android.app.VoiceInteractor;
     20 import android.app.VoiceInteractor.Prompt;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.pm.LauncherApps;
     24 import android.os.AsyncTask;
     25 import android.os.Bundle;
     26 import android.service.voice.VoiceInteractionSession;
     27 import android.service.voice.VoiceInteractionSession.ConfirmationRequest;
     28 import android.service.voice.VoiceInteractionSession.PickOptionRequest;
     29 import android.util.Log;
     30 import android.voiceinteraction.common.Utils;
     31 
     32 import java.util.ArrayList;
     33 import java.util.List;
     34 
     35 
     36 public class MainInteractionSession extends VoiceInteractionSession {
     37     static final String TAG = "MainInteractionSession";
     38 
     39     Intent mStartIntent;
     40     List<MyTask> mUsedTasks = new ArrayList<MyTask>();
     41 
     42     MainInteractionSession(Context context) {
     43         super(context);
     44     }
     45 
     46     @Override
     47     public void onCreate() {
     48         super.onCreate();
     49         Intent sessionStarted = new Intent();
     50         sessionStarted.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
     51         if (!getContext().getSystemService(LauncherApps.class).hasShortcutHostPermission()) {
     52             sessionStarted.putExtra("error", "Does not have shortcut permission");
     53         }
     54         sessionStarted.setClassName("android.voiceinteraction.cts",
     55                 "android.voiceinteraction.cts.VoiceInteractionTestReceiver");
     56         getContext().sendBroadcast(sessionStarted);
     57     }
     58 
     59     @Override
     60     public void onDestroy() {
     61         Log.i(TAG, "Canceling the Asynctask in onDestroy()");
     62         for (MyTask t : mUsedTasks) {
     63             t.cancel(true);
     64         }
     65         super.onDestroy();
     66     }
     67 
     68     @Override
     69     public void onShow(Bundle args, int showFlags) {
     70         super.onShow(args, showFlags);
     71         mStartIntent = args.getParcelable("intent");
     72         if (mStartIntent != null) {
     73             startVoiceActivity(mStartIntent);
     74         } else if ((showFlags & SHOW_SOURCE_ACTIVITY) == SHOW_SOURCE_ACTIVITY) {
     75             // Verify args
     76             if (args == null
     77                     || !Utils.PRIVATE_OPTIONS_VALUE.equals(
     78                             args.getString(Utils.PRIVATE_OPTIONS_KEY))) {
     79                 throw new IllegalArgumentException("Incorrect arguments for SHOW_SOURCE_ACTIVITY");
     80             }
     81         }
     82     }
     83 
     84     void assertPromptFromTestApp(CharSequence prompt, Bundle extras) {
     85         String str = prompt.toString();
     86         if (str.equals(Utils.TEST_PROMPT)) {
     87             Log.i(TAG, "prompt received ok from TestApp in Session");
     88         } else {
     89             Utils.addErrorResult(extras, "Invalid prompt received: " + str);
     90         }
     91     }
     92 
     93     synchronized MyTask newTask() {
     94         MyTask t = new MyTask();
     95         mUsedTasks.add(t);
     96         return t;
     97     }
     98 
     99     @Override
    100     public boolean[] onGetSupportedCommands(String[] commands) {
    101         boolean[] results = new boolean[commands.length];
    102         Log.i(TAG, "in onGetSupportedCommands");
    103         for (int idx = 0; idx < commands.length; idx++) {
    104             results[idx] = Utils.TEST_COMMAND.equals(commands[idx]);
    105             Log.i(TAG, "command " + commands[idx] + ", support = " + results[idx]);
    106         }
    107         return results;
    108     }
    109 
    110     @Override
    111     public void onRequestConfirmation(ConfirmationRequest request) {
    112         Bundle extras = request.getExtras();
    113         CharSequence prompt = request.getVoicePrompt().getVoicePromptAt(0);
    114         Log.i(TAG, "in Session onRequestConfirmation recvd. prompt=" + prompt +
    115                 ", extras=" + Utils.toBundleString(extras));
    116         assertPromptFromTestApp(prompt, extras);
    117         AsyncTaskArg asyncTaskArg = new AsyncTaskArg().setRequest(request).setExtras(extras);
    118         if (isTestTypeCancel(extras)) {
    119             Log.i(TAG, "Sending Cancel.");
    120             newTask().execute(
    121                     asyncTaskArg.setTestType(Utils.TestCaseType.CONFIRMATION_REQUEST_CANCEL_TEST));
    122         } else {
    123             Log.i(TAG, "in Session sending sendConfirmationResult. " +
    124                     Utils.toBundleString(extras));
    125             newTask().execute(
    126                     asyncTaskArg.setTestType(Utils.TestCaseType.CONFIRMATION_REQUEST_TEST));
    127         }
    128     }
    129 
    130     @Override
    131     public void onRequestCompleteVoice(CompleteVoiceRequest request) {
    132         Bundle extras = request.getExtras();
    133         CharSequence prompt = request.getVoicePrompt().getVoicePromptAt(0);
    134         Log.i(TAG, "in Session onRequestCompleteVoice recvd. message=" +
    135                 prompt + ", extras=" + Utils.toBundleString(extras));
    136         assertPromptFromTestApp(prompt, extras);
    137         AsyncTaskArg asyncTaskArg = new AsyncTaskArg().setRequest(request).setExtras(extras);
    138         if (isTestTypeCancel(extras)) {
    139             Log.i(TAG, "Sending Cancel.");
    140             newTask().execute(
    141                     asyncTaskArg.setTestType(Utils.TestCaseType.COMPLETION_REQUEST_CANCEL_TEST));
    142         } else {
    143             Log.i(TAG, "in Session sending sendConfirmationResult. " +
    144                     Utils.toBundleString(extras));
    145             newTask().execute(
    146                     asyncTaskArg.setTestType(Utils.TestCaseType.COMPLETION_REQUEST_TEST));
    147         }
    148     }
    149 
    150     @Override
    151     public void onRequestAbortVoice(AbortVoiceRequest request) {
    152         Bundle extras = request.getExtras();
    153         CharSequence prompt = request.getVoicePrompt().getVoicePromptAt(0);
    154         Log.i(TAG, "in Session onRequestAbortVoice recvd. message=" +
    155                 prompt + ", extras=" + Utils.toBundleString(extras));
    156         assertPromptFromTestApp(prompt, extras);
    157         AsyncTaskArg asyncTaskArg = new AsyncTaskArg().setRequest(request).setExtras(extras);
    158         if (isTestTypeCancel(extras)) {
    159             Log.i(TAG, "Sending Cancel.");
    160             newTask().execute(
    161                     asyncTaskArg.setTestType(Utils.TestCaseType.ABORT_REQUEST_CANCEL_TEST));
    162         } else {
    163             Log.i(TAG, "in Session sending sendAbortResult. " +
    164                 Utils.toBundleString(extras));
    165             newTask().execute(asyncTaskArg.setTestType(Utils.TestCaseType.ABORT_REQUEST_TEST));
    166         }
    167     }
    168 
    169     @Override
    170     public void onRequestCommand(CommandRequest request) {
    171         Bundle extras = request.getExtras();
    172         Log.i(TAG, "in Session onRequestCommand recvd. Bundle = " +
    173                 Utils.toBundleString(extras));
    174 
    175         // Make sure that the input request has Utils.TEST_COMMAND sent by TestApp
    176         String command = request.getCommand();
    177         if (command.equals(Utils.TEST_COMMAND)) {
    178             Log.i(TAG, "command received ok from TestApp in Session");
    179         } else {
    180             Utils.addErrorResult(extras, "Invalid TEST_COMMAND received: " + command);
    181         }
    182         // Add a field and value in the bundle to be sent to TestApp.
    183         // TestApp will ensure that these are transmitted correctly.
    184         extras.putString(Utils.TEST_ONCOMMAND_RESULT, Utils.TEST_ONCOMMAND_RESULT_VALUE);
    185         AsyncTaskArg asyncTaskArg = new AsyncTaskArg().setRequest(request).setExtras(extras);
    186         if (isTestTypeCancel(extras)) {
    187             Log.i(TAG, "Sending Cancel.");
    188             newTask().execute(
    189                     asyncTaskArg.setTestType(Utils.TestCaseType.COMMANDREQUEST_CANCEL_TEST));
    190         } else {
    191             Log.i(TAG, "in Session sending sendResult. " +
    192                     Utils.toBundleString(extras) + ", string_in_bundle: " +
    193                     Utils.TEST_ONCOMMAND_RESULT + " = " + Utils.TEST_ONCOMMAND_RESULT_VALUE);
    194             newTask().execute(asyncTaskArg.setTestType(Utils.TestCaseType.COMMANDREQUEST_TEST));
    195         }
    196     }
    197 
    198     void assertPickOptionsFromTestApp(VoiceInteractor.PickOptionRequest.Option[] options,
    199             Bundle extras) {
    200         if ((options.length != 2) ||
    201             !options[0].getLabel().toString().equals(Utils.PICKOPTON_1) ||
    202             !options[1].getLabel().toString().equals(Utils.PICKOPTON_2)) {
    203             Utils.addErrorResult(extras, "Pickoptions Not received correctly in Session.");
    204         } else {
    205             Log.i(TAG, "Pickoptions received ok from TestApp in Session");
    206         }
    207     }
    208 
    209     @Override
    210     public void onRequestPickOption(PickOptionRequest request) {
    211         Bundle extras = request.getExtras();
    212         CharSequence prompt = request.getVoicePrompt().getVoicePromptAt(0);
    213         Log.i(TAG, "in Session onRequestPickOption recvd. message=" +
    214                 prompt + ", options = " + Utils.toOptionsString(request.getOptions()) +
    215                 ", extras=" + Utils.toBundleString(extras));
    216         VoiceInteractor.PickOptionRequest.Option[] picked
    217             = new VoiceInteractor.PickOptionRequest.Option[1];
    218         assertPromptFromTestApp(prompt, extras);
    219         assertPickOptionsFromTestApp(request.getOptions(), extras);
    220         picked[0] = new VoiceInteractor.PickOptionRequest.Option(Utils.PICKOPTON_3, 0);
    221         AsyncTaskArg asyncTaskArg = new AsyncTaskArg().setRequest(request)
    222                 .setExtras(extras)
    223                 .setPickedOptions(picked);
    224         if (isTestTypeCancel(extras)) {
    225             Log.i(TAG, "in MainInteractionSession, Sending Cancel.");
    226             newTask().execute(
    227                     asyncTaskArg.setTestType(Utils.TestCaseType.PICKOPTION_REQUEST_CANCEL_TEST));
    228         } else {
    229             Log.i(TAG, "in MainInteractionSession sending sendPickOptionResult. " +
    230                     Utils.toBundleString(extras));
    231             newTask().execute(asyncTaskArg.setTestType(Utils.TestCaseType.PICKOPTION_REQUEST_TEST));
    232         }
    233     }
    234 
    235     public static final boolean isTestTypeCancel(Bundle extras) {
    236         Utils.TestCaseType testCaseType;
    237         try {
    238             testCaseType = Utils.TestCaseType.valueOf(extras.getString(Utils.TESTCASE_TYPE));
    239         } catch (IllegalArgumentException | NullPointerException e) {
    240             Log.wtf(TAG, "unexpected testCaseType value in Bundle received", e);
    241             return true;
    242         }
    243         return testCaseType == Utils.TestCaseType.COMPLETION_REQUEST_CANCEL_TEST ||
    244                 testCaseType == Utils.TestCaseType.COMMANDREQUEST_CANCEL_TEST ||
    245                 testCaseType == Utils.TestCaseType.CONFIRMATION_REQUEST_CANCEL_TEST ||
    246                 testCaseType == Utils.TestCaseType.PICKOPTION_REQUEST_CANCEL_TEST ||
    247                 testCaseType == Utils.TestCaseType.ABORT_REQUEST_CANCEL_TEST;
    248     }
    249 
    250     private class AsyncTaskArg {
    251         ConfirmationRequest confReq;
    252         CommandRequest commandReq;
    253         CompleteVoiceRequest compReq;
    254         AbortVoiceRequest abortReq;
    255         PickOptionRequest pickReq;
    256         Bundle extras;
    257         VoiceInteractor.PickOptionRequest.Option[] picked;
    258         Utils.TestCaseType testType;
    259 
    260         AsyncTaskArg setTestType(Utils.TestCaseType t) {testType = t; return this;}
    261         AsyncTaskArg setRequest(CommandRequest r) {commandReq = r; return this;}
    262         AsyncTaskArg setRequest(ConfirmationRequest r) {confReq = r; return this;}
    263         AsyncTaskArg setRequest(CompleteVoiceRequest r) {compReq = r; return this;}
    264         AsyncTaskArg setRequest(AbortVoiceRequest r) {abortReq = r; return this;}
    265         AsyncTaskArg setRequest(PickOptionRequest r) {pickReq = r; return this;}
    266         AsyncTaskArg setExtras(Bundle e) {extras = e;  return this;}
    267         AsyncTaskArg setPickedOptions(VoiceInteractor.PickOptionRequest.Option[] p) {
    268             picked = p;
    269             return this;
    270         }
    271     }
    272 
    273     private class MyTask extends AsyncTask<AsyncTaskArg, Void, Void> {
    274         @Override
    275         protected Void doInBackground(AsyncTaskArg... params) {
    276             AsyncTaskArg arg = params[0];
    277             Log.i(TAG, "in MyTask - doInBackground: requestType = " +
    278                     arg.testType.toString());
    279             switch (arg.testType) {
    280                 case ABORT_REQUEST_CANCEL_TEST:
    281                     arg.abortReq.cancel();
    282                     break;
    283                 case ABORT_REQUEST_TEST:
    284                     arg.abortReq.sendAbortResult(arg.extras);
    285                     break;
    286                 case COMMANDREQUEST_CANCEL_TEST:
    287                     arg.commandReq.cancel();
    288                     break;
    289                 case COMMANDREQUEST_TEST:
    290                     Log.i(TAG, "in MyTask sendResult. " +
    291                             Utils.toBundleString(arg.extras) + ", string_in_bundle: " +
    292                             Utils.TEST_ONCOMMAND_RESULT + " = " +
    293                             Utils.TEST_ONCOMMAND_RESULT_VALUE);
    294                     arg.commandReq.sendResult(arg.extras);
    295                     break;
    296                 case COMPLETION_REQUEST_CANCEL_TEST:
    297                     arg.compReq.cancel();
    298                     break;
    299                 case COMPLETION_REQUEST_TEST:
    300                     arg.compReq.sendCompleteResult(arg.extras);
    301                     break;
    302                 case CONFIRMATION_REQUEST_CANCEL_TEST:
    303                      arg.confReq.cancel();
    304                      break;
    305                 case CONFIRMATION_REQUEST_TEST:
    306                      arg.confReq.sendConfirmationResult(true, arg.extras);
    307                      break;
    308                 case PICKOPTION_REQUEST_CANCEL_TEST:
    309                      arg.pickReq.cancel();
    310                      break;
    311                 case PICKOPTION_REQUEST_TEST:
    312                      StringBuilder buf = new StringBuilder();
    313                      for (VoiceInteractor.PickOptionRequest.Option s : arg.picked) {
    314                          buf.append("option: " + s.toString() + ", ");
    315                      }
    316                      Log.i(TAG, "******** Sending PickoptionResult: " +
    317                              "picked: size = " + arg.picked.length +
    318                              ", Options = " + buf.toString() +
    319                              ", Bundle: " + Utils.toBundleString(arg.extras));
    320                      arg.pickReq.sendPickOptionResult(arg.picked, arg.extras);
    321                      break;
    322                default:
    323                    Log.i(TAG, "Doing nothing for the testcase type: " + arg.testType);
    324                    break;
    325             }
    326             return null;
    327         }
    328     }
    329 }
    330