MainInteractionSession.java revision e8222e551f8abd2d82ca4f77ddb275e2e509751e
1/* 2 * Copyright (C) 2014 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 17package com.android.test.voiceinteraction; 18 19import android.app.ActivityManager; 20import android.app.VoiceInteractor; 21import android.app.assist.AssistContent; 22import android.app.assist.AssistStructure; 23import android.content.Context; 24import android.content.Intent; 25import android.graphics.Bitmap; 26import android.net.Uri; 27import android.os.Bundle; 28import android.service.voice.VoiceInteractionSession; 29import android.util.Log; 30import android.view.View; 31import android.widget.Button; 32import android.widget.CheckBox; 33import android.widget.ImageView; 34import android.widget.TextView; 35 36public class MainInteractionSession extends VoiceInteractionSession 37 implements View.OnClickListener { 38 static final String TAG = "MainInteractionSession"; 39 40 Intent mStartIntent; 41 View mContentView; 42 AssistVisualizer mAssistVisualizer; 43 View mTopContent; 44 View mBottomContent; 45 TextView mText; 46 Button mTreeButton; 47 Button mTextButton; 48 Button mStartButton; 49 CheckBox mOptionsCheck; 50 View mOptionsContainer; 51 CheckBox mDisallowAssist; 52 CheckBox mDisallowScreenshot; 53 TextView mOptionsText; 54 ImageView mScreenshot; 55 ImageView mFullScreenshot; 56 Button mConfirmButton; 57 Button mCompleteButton; 58 Button mAbortButton; 59 60 AssistStructure mAssistStructure; 61 62 static final int STATE_IDLE = 0; 63 static final int STATE_LAUNCHING = 1; 64 static final int STATE_CONFIRM = 2; 65 static final int STATE_PICK_OPTION = 3; 66 static final int STATE_COMMAND = 4; 67 static final int STATE_ABORT_VOICE = 5; 68 static final int STATE_COMPLETE_VOICE = 6; 69 static final int STATE_DONE = 7; 70 71 int mState = STATE_IDLE; 72 VoiceInteractor.PickOptionRequest.Option[] mPendingOptions; 73 CharSequence mPendingPrompt; 74 Request mPendingRequest; 75 int mCurrentTask = -1; 76 int mShowFlags; 77 78 MainInteractionSession(Context context) { 79 super(context); 80 } 81 82 @Override 83 public void onCreate() { 84 super.onCreate(); 85 ActivityManager am = getContext().getSystemService(ActivityManager.class); 86 am.setWatchHeapLimit(40 * 1024 * 1024); 87 } 88 89 @Override 90 public void onShow(Bundle args, int showFlags) { 91 super.onShow(args, showFlags); 92 mShowFlags = showFlags; 93 Log.i(TAG, "onShow: flags=0x" + Integer.toHexString(showFlags) + " args=" + args); 94 mState = STATE_IDLE; 95 mStartIntent = args != null ? (Intent)args.getParcelable("intent") : null; 96 if (mStartIntent == null) { 97 mStartIntent = new Intent(getContext(), TestInteractionActivity.class); 98 } 99 if (mAssistVisualizer != null) { 100 mAssistVisualizer.clearAssistData(); 101 } 102 onHandleScreenshot(null); 103 updateState(); 104 refreshOptions(); 105 } 106 107 @Override 108 public void onHide() { 109 super.onHide(); 110 if (mAssistVisualizer != null) { 111 mAssistVisualizer.clearAssistData(); 112 } 113 mState = STATE_DONE; 114 updateState(); 115 } 116 117 @Override 118 public View onCreateContentView() { 119 mContentView = getLayoutInflater().inflate(R.layout.voice_interaction_session, null); 120 mAssistVisualizer = (AssistVisualizer)mContentView.findViewById(R.id.assist_visualizer); 121 if (mAssistStructure != null) { 122 mAssistVisualizer.setAssistStructure(mAssistStructure); 123 } 124 mTopContent = mContentView.findViewById(R.id.top_content); 125 mBottomContent = mContentView.findViewById(R.id.bottom_content); 126 mText = (TextView)mContentView.findViewById(R.id.text); 127 mTreeButton = (Button)mContentView.findViewById(R.id.do_tree); 128 mTreeButton.setOnClickListener(this); 129 mTextButton = (Button)mContentView.findViewById(R.id.do_text); 130 mTextButton.setOnClickListener(this); 131 mStartButton = (Button)mContentView.findViewById(R.id.start); 132 mStartButton.setOnClickListener(this); 133 mScreenshot = (ImageView)mContentView.findViewById(R.id.screenshot); 134 mScreenshot.setOnClickListener(this); 135 mFullScreenshot = (ImageView)mContentView.findViewById(R.id.full_screenshot); 136 mOptionsCheck = (CheckBox)mContentView.findViewById(R.id.show_options); 137 mOptionsCheck.setOnClickListener(this); 138 mOptionsContainer = mContentView.findViewById(R.id.options); 139 mDisallowAssist = (CheckBox)mContentView.findViewById(R.id.disallow_structure); 140 mDisallowAssist.setOnClickListener(this); 141 mDisallowScreenshot = (CheckBox)mContentView.findViewById(R.id.disallow_screenshot); 142 mDisallowScreenshot.setOnClickListener(this); 143 mOptionsText = (TextView)mContentView.findViewById(R.id.options_text); 144 mConfirmButton = (Button)mContentView.findViewById(R.id.confirm); 145 mConfirmButton.setOnClickListener(this); 146 mCompleteButton = (Button)mContentView.findViewById(R.id.complete); 147 mCompleteButton.setOnClickListener(this); 148 mAbortButton = (Button)mContentView.findViewById(R.id.abort); 149 mAbortButton.setOnClickListener(this); 150 refreshOptions(); 151 return mContentView; 152 } 153 154 void refreshOptions() { 155 if (mOptionsContainer != null) { 156 if (mOptionsCheck.isChecked()) { 157 mOptionsContainer.setVisibility(View.VISIBLE); 158 int flags = getDisabledShowContext(); 159 mDisallowAssist.setChecked((flags & SHOW_WITH_ASSIST) != 0); 160 mDisallowScreenshot.setChecked((flags & SHOW_WITH_SCREENSHOT) != 0); 161 int disabled = getUserDisabledShowContext(); 162 mOptionsText.setText("Disabled: 0x" + Integer.toHexString(disabled)); 163 } else { 164 mOptionsContainer.setVisibility(View.GONE); 165 } 166 } 167 } 168 169 public void onHandleAssist(Bundle assistBundle) { 170 } 171 172 @Override 173 public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) { 174 mAssistStructure = structure; 175 if (mAssistStructure != null) { 176 if (mAssistVisualizer != null) { 177 mAssistVisualizer.setAssistStructure(mAssistStructure); 178 } 179 } else { 180 if (mAssistVisualizer != null) { 181 mAssistVisualizer.clearAssistData(); 182 } 183 } 184 if (content != null) { 185 Log.i(TAG, "Assist intent: " + content.getIntent()); 186 Log.i(TAG, "Assist clipdata: " + content.getClipData()); 187 } 188 if (data != null) { 189 Uri referrer = data.getParcelable(Intent.EXTRA_REFERRER); 190 if (referrer != null) { 191 Log.i(TAG, "Referrer: " + referrer); 192 } 193 } 194 } 195 196 @Override 197 public void onHandleAssistSecondary(final Bundle data, final AssistStructure structure, 198 final AssistContent content, int index, int count) { 199 Log.i(TAG, "Got secondary activity assist data " + index + " of " + count); 200 Log.i(TAG, "Showing assist structure after a few seconds..."); 201 mContentView.postDelayed(new Runnable() { 202 public void run() { 203 onHandleAssist(data, structure, content); 204 } 205 }, 2000 * index); 206 } 207 208 @Override 209 public void onHandleScreenshot(Bitmap screenshot) { 210 if (screenshot != null) { 211 mScreenshot.setImageBitmap(screenshot); 212 mScreenshot.setAdjustViewBounds(true); 213 mScreenshot.setMaxWidth(screenshot.getWidth() / 3); 214 mScreenshot.setMaxHeight(screenshot.getHeight() / 3); 215 mFullScreenshot.setImageBitmap(screenshot); 216 } else { 217 mScreenshot.setImageDrawable(null); 218 mFullScreenshot.setImageDrawable(null); 219 } 220 } 221 222 void updateState() { 223 if (mState == STATE_IDLE) { 224 mTopContent.setVisibility(View.VISIBLE); 225 mBottomContent.setVisibility(View.GONE); 226 mAssistVisualizer.setVisibility(View.VISIBLE); 227 } else if (mState == STATE_DONE) { 228 mTopContent.setVisibility(View.GONE); 229 mBottomContent.setVisibility(View.GONE); 230 mAssistVisualizer.setVisibility(View.GONE); 231 } else { 232 mTopContent.setVisibility(View.GONE); 233 mBottomContent.setVisibility(View.VISIBLE); 234 mAssistVisualizer.setVisibility(View.GONE); 235 } 236 mStartButton.setEnabled(mState == STATE_IDLE); 237 mConfirmButton.setEnabled(mState == STATE_CONFIRM || mState == STATE_PICK_OPTION 238 || mState == STATE_COMMAND); 239 mAbortButton.setEnabled(mState == STATE_ABORT_VOICE); 240 mCompleteButton.setEnabled(mState == STATE_COMPLETE_VOICE); 241 } 242 243 public void onClick(View v) { 244 if (v == mTreeButton) { 245 if (mAssistVisualizer != null) { 246 mAssistVisualizer.logTree(); 247 } 248 } else if (v == mTextButton) { 249 if (mAssistVisualizer != null) { 250 mAssistVisualizer.logText(); 251 } 252 } else if (v == mOptionsCheck) { 253 refreshOptions(); 254 } else if (v == mDisallowAssist) { 255 int flags = getDisabledShowContext(); 256 if (mDisallowAssist.isChecked()) { 257 flags |= SHOW_WITH_ASSIST; 258 } else { 259 flags &= ~SHOW_WITH_ASSIST; 260 } 261 setDisabledShowContext(flags); 262 } else if (v == mDisallowScreenshot) { 263 int flags = getDisabledShowContext(); 264 if (mDisallowScreenshot.isChecked()) { 265 flags |= SHOW_WITH_SCREENSHOT; 266 } else { 267 flags &= ~SHOW_WITH_SCREENSHOT; 268 } 269 setDisabledShowContext(flags); 270 } else if (v == mStartButton) { 271 mState = STATE_LAUNCHING; 272 updateState(); 273 startVoiceActivity(mStartIntent); 274 } else if (v == mConfirmButton) { 275 if (mPendingRequest instanceof ConfirmationRequest) { 276 ((ConfirmationRequest)mPendingRequest).sendConfirmationResult(true, null); 277 mPendingRequest = null; 278 mState = STATE_LAUNCHING; 279 } else if (mPendingRequest instanceof PickOptionRequest) { 280 PickOptionRequest pick = (PickOptionRequest)mPendingRequest; 281 int numReturn = mPendingOptions.length/2; 282 if (numReturn <= 0) { 283 numReturn = 1; 284 } 285 VoiceInteractor.PickOptionRequest.Option[] picked 286 = new VoiceInteractor.PickOptionRequest.Option[numReturn]; 287 for (int i=0; i<picked.length; i++) { 288 picked[i] = mPendingOptions[i*2]; 289 } 290 mPendingOptions = picked; 291 if (picked.length <= 1) { 292 pick.sendPickOptionResult(picked, null); 293 mPendingRequest = null; 294 mState = STATE_LAUNCHING; 295 } else { 296 pick.sendIntermediatePickOptionResult(picked, null); 297 updatePickText(); 298 } 299 } else if (mPendingRequest instanceof CommandRequest) { 300 Bundle result = new Bundle(); 301 result.putString("key", "a result!"); 302 ((CommandRequest)mPendingRequest).sendResult(result); 303 mPendingRequest = null; 304 mState = STATE_LAUNCHING; 305 } 306 } else if (v == mAbortButton && mPendingRequest instanceof AbortVoiceRequest) { 307 ((AbortVoiceRequest)mPendingRequest).sendAbortResult(null); 308 mPendingRequest = null; 309 } else if (v == mCompleteButton && mPendingRequest instanceof CompleteVoiceRequest) { 310 ((CompleteVoiceRequest)mPendingRequest).sendCompleteResult(null); 311 mPendingRequest = null; 312 } else if (v == mScreenshot) { 313 if (mFullScreenshot.getVisibility() != View.VISIBLE) { 314 mFullScreenshot.setVisibility(View.VISIBLE); 315 } else { 316 mFullScreenshot.setVisibility(View.INVISIBLE); 317 } 318 } 319 updateState(); 320 } 321 322 @Override 323 public void onComputeInsets(Insets outInsets) { 324 super.onComputeInsets(outInsets); 325 if (mState != STATE_IDLE) { 326 outInsets.contentInsets.top = mBottomContent.getTop(); 327 outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_CONTENT; 328 } else if ((mShowFlags & SHOW_SOURCE_ACTIVITY) != 0) { 329 outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_CONTENT; 330 } 331 } 332 333 @Override 334 public void onTaskStarted(Intent intent, int taskId) { 335 super.onTaskStarted(intent, taskId); 336 mCurrentTask = taskId; 337 } 338 339 @Override 340 public void onTaskFinished(Intent intent, int taskId) { 341 super.onTaskFinished(intent, taskId); 342 if (mCurrentTask == taskId) { 343 mCurrentTask = -1; 344 } 345 } 346 347 @Override 348 public void onLockscreenShown() { 349 if (mCurrentTask < 0) { 350 hide(); 351 } 352 } 353 354 @Override 355 public boolean[] onGetSupportedCommands(String[] commands) { 356 boolean[] res = new boolean[commands.length]; 357 for (int i=0; i<commands.length; i++) { 358 if ("com.android.test.voiceinteraction.COMMAND".equals(commands[i])) { 359 res[i] = true; 360 } 361 } 362 return res; 363 } 364 365 void setPrompt(VoiceInteractor.Prompt prompt) { 366 if (prompt == null) { 367 mText.setText("(null)"); 368 mPendingPrompt = ""; 369 } else { 370 mText.setText(prompt.getVisualPrompt()); 371 mPendingPrompt = prompt.getVisualPrompt(); 372 } 373 } 374 375 @Override 376 public void onRequestConfirmation(ConfirmationRequest request) { 377 Log.i(TAG, "onConfirm: prompt=" + request.getVoicePrompt() + " extras=" 378 + request.getExtras()); 379 setPrompt(request.getVoicePrompt()); 380 mConfirmButton.setText("Confirm"); 381 mPendingRequest = request; 382 mState = STATE_CONFIRM; 383 updateState(); 384 } 385 386 @Override 387 public void onRequestPickOption(PickOptionRequest request) { 388 Log.i(TAG, "onPickOption: prompt=" + request.getVoicePrompt() + " options=" 389 + request.getOptions() + " extras=" + request.getExtras()); 390 mConfirmButton.setText("Pick Option"); 391 mPendingRequest = request; 392 setPrompt(request.getVoicePrompt()); 393 mPendingOptions = request.getOptions(); 394 mState = STATE_PICK_OPTION; 395 updatePickText(); 396 updateState(); 397 } 398 399 void updatePickText() { 400 StringBuilder sb = new StringBuilder(); 401 sb.append(mPendingPrompt); 402 sb.append(": "); 403 for (int i=0; i<mPendingOptions.length; i++) { 404 if (i > 0) { 405 sb.append(", "); 406 } 407 sb.append(mPendingOptions[i].getLabel()); 408 } 409 mText.setText(sb.toString()); 410 } 411 412 @Override 413 public void onRequestCompleteVoice(CompleteVoiceRequest request) { 414 Log.i(TAG, "onCompleteVoice: message=" + request.getVoicePrompt() + " extras=" 415 + request.getExtras()); 416 setPrompt(request.getVoicePrompt()); 417 mPendingRequest = request; 418 mState = STATE_COMPLETE_VOICE; 419 updateState(); 420 } 421 422 @Override 423 public void onRequestAbortVoice(AbortVoiceRequest request) { 424 Log.i(TAG, "onAbortVoice: message=" + request.getVoicePrompt() + " extras=" 425 + request.getExtras()); 426 setPrompt(request.getVoicePrompt()); 427 mPendingRequest = request; 428 mState = STATE_ABORT_VOICE; 429 updateState(); 430 } 431 432 @Override 433 public void onRequestCommand(CommandRequest request) { 434 Bundle extras = request.getExtras(); 435 if (extras != null) { 436 extras.getString("arg"); 437 } 438 Log.i(TAG, "onCommand: command=" + request.getCommand() + " extras=" + extras); 439 mText.setText("Command: " + request.getCommand() + ", " + extras); 440 mConfirmButton.setText("Finish Command"); 441 mPendingRequest = request; 442 mState = STATE_COMMAND; 443 updateState(); 444 } 445 446 @Override 447 public void onCancelRequest(Request request) { 448 Log.i(TAG, "onCancel"); 449 if (mPendingRequest == request) { 450 mPendingRequest = null; 451 mState = STATE_LAUNCHING; 452 updateState(); 453 } 454 request.cancel(); 455 } 456} 457