aboutsummaryrefslogtreecommitdiff
path: root/src/io/appium/droiddriver/actions/view/CloseKeyboardAction.java
blob: d65339765435fbb9a2c7b85b1c91fc7a3256dc75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
 * Copyright (C) 2015 DroidDriver committers
 *
 * 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 io.appium.droiddriver.actions.view;

import android.content.Context;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;

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

import io.appium.droiddriver.UiElement;
import io.appium.droiddriver.exceptions.ActionException;
import io.appium.droiddriver.exceptions.DroidDriverException;
import io.appium.droiddriver.util.InstrumentationUtils;
import io.appium.droiddriver.util.Logs;

/**
 * Closes soft keyboard. Based on the <a href="https://code.google.com/p/android-test-kit/wiki/Espresso">Espresso</a>
 * code under the same name.
 */
public class CloseKeyboardAction extends ViewAction {
  /** Defaults timeoutMillis to 2000 */
  public static final CloseKeyboardAction DEFAULT_INSTANCE = new CloseKeyboardAction(2000L, 1000L);

  private final long keyboardDismissalDelayMillis;

  /**
   * @param timeoutMillis                the value returned by {@link #getTimeoutMillis}
   * @param keyboardDismissalDelayMillis <a href="https://code.google.com/p/android-test-kit/issues/detail?id=79#c7">a
   *                                     delay for the soft keyboard to finish closing</a>
   */
  public CloseKeyboardAction(long timeoutMillis, long keyboardDismissalDelayMillis) {
    super(timeoutMillis);
    this.keyboardDismissalDelayMillis = keyboardDismissalDelayMillis;
  }

  protected boolean perform(View view, UiElement element) {
    InputMethodManager imm = (InputMethodManager) InstrumentationUtils.getTargetContext()
        .getSystemService(Context.INPUT_METHOD_SERVICE);
    final AtomicInteger resultCodeHolder = new AtomicInteger();
    final CountDownLatch latch = new CountDownLatch(1);

    ResultReceiver resultReceiver = new ResultReceiver(null) {
      @Override
      protected void onReceiveResult(int resultCode, Bundle resultData) {
        resultCodeHolder.set(resultCode);
        latch.countDown();
      }
    };

    if (!imm.hideSoftInputFromWindow(view.getWindowToken(), 0, resultReceiver)) {
      Logs.log(Log.INFO, "InputMethodManager.hideSoftInputFromWindow returned false");
      // Soft keyboard is not shown if hideSoftInputFromWindow returned false
      return true;
    }

    try {
      if (!latch.await(getTimeoutMillis(), TimeUnit.MILLISECONDS)) {
        throw new ActionException("Timed out after " + getTimeoutMillis() + " milliseconds" +
            " waiting for resultCode from InputMethodManager.hideSoftInputFromWindow");
      }
    } catch (InterruptedException e) {
      throw DroidDriverException.propagate(e);
    }

    int resultCode = resultCodeHolder.get();
    if (resultCode != InputMethodManager.RESULT_UNCHANGED_HIDDEN
        && resultCode != InputMethodManager.RESULT_HIDDEN) {
      throw new ActionException("resultCode from InputMethodManager.hideSoftInputFromWindow="
          + resultCode);
    }

    // Wait for the soft keyboard to finish closing
    SystemClock.sleep(keyboardDismissalDelayMillis);
    return true;
  }

  @Override
  public String toString() {
    return getClass().getSimpleName();
  }
}