1baf412994612ae72a3db9698b1d216078297b48aChris Craik/*
2baf412994612ae72a3db9698b1d216078297b48aChris Craik * Copyright (C) 2015 The Android Open Source Project
3baf412994612ae72a3db9698b1d216078297b48aChris Craik *
4baf412994612ae72a3db9698b1d216078297b48aChris Craik * Licensed under the Apache License, Version 2.0 (the "License");
5baf412994612ae72a3db9698b1d216078297b48aChris Craik * you may not use this file except in compliance with the License.
6baf412994612ae72a3db9698b1d216078297b48aChris Craik * You may obtain a copy of the License at
7baf412994612ae72a3db9698b1d216078297b48aChris Craik *
8baf412994612ae72a3db9698b1d216078297b48aChris Craik *      http://www.apache.org/licenses/LICENSE-2.0
9baf412994612ae72a3db9698b1d216078297b48aChris Craik *
10baf412994612ae72a3db9698b1d216078297b48aChris Craik * Unless required by applicable law or agreed to in writing, software
11baf412994612ae72a3db9698b1d216078297b48aChris Craik * distributed under the License is distributed on an "AS IS" BASIS,
12baf412994612ae72a3db9698b1d216078297b48aChris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13baf412994612ae72a3db9698b1d216078297b48aChris Craik * See the License for the specific language governing permissions and
14baf412994612ae72a3db9698b1d216078297b48aChris Craik * limitations under the License.
15baf412994612ae72a3db9698b1d216078297b48aChris Craik */
16baf412994612ae72a3db9698b1d216078297b48aChris Craikpackage com.android.test.uibench;
17baf412994612ae72a3db9698b1d216078297b48aChris Craik
18baf412994612ae72a3db9698b1d216078297b48aChris Craikimport android.app.Instrumentation;
19baf412994612ae72a3db9698b1d216078297b48aChris Craikimport android.os.Bundle;
20baf412994612ae72a3db9698b1d216078297b48aChris Craikimport android.os.Looper;
21baf412994612ae72a3db9698b1d216078297b48aChris Craikimport android.os.MessageQueue;
22baf412994612ae72a3db9698b1d216078297b48aChris Craikimport android.support.v7.app.AppCompatActivity;
23baf412994612ae72a3db9698b1d216078297b48aChris Craikimport android.view.KeyEvent;
24baf412994612ae72a3db9698b1d216078297b48aChris Craikimport android.widget.EditText;
25baf412994612ae72a3db9698b1d216078297b48aChris Craik
26baf412994612ae72a3db9698b1d216078297b48aChris Craikimport java.util.concurrent.Semaphore;
27baf412994612ae72a3db9698b1d216078297b48aChris Craik
28baf412994612ae72a3db9698b1d216078297b48aChris Craik/**
29baf412994612ae72a3db9698b1d216078297b48aChris Craik * Note: currently incomplete, complexity of input continuously grows, instead of looping
30baf412994612ae72a3db9698b1d216078297b48aChris Craik * over a stable amount of work.
31baf412994612ae72a3db9698b1d216078297b48aChris Craik *
32baf412994612ae72a3db9698b1d216078297b48aChris Craik * Simulates typing continuously into an EditText.
33baf412994612ae72a3db9698b1d216078297b48aChris Craik */
34baf412994612ae72a3db9698b1d216078297b48aChris Craikpublic class EditTextTypeActivity extends AppCompatActivity {
35baf412994612ae72a3db9698b1d216078297b48aChris Craik    Thread mThread;
36baf412994612ae72a3db9698b1d216078297b48aChris Craik
37baf412994612ae72a3db9698b1d216078297b48aChris Craik    private static String sSeedText = "";
38baf412994612ae72a3db9698b1d216078297b48aChris Craik    static {
39baf412994612ae72a3db9698b1d216078297b48aChris Craik        final int count = 100;
40baf412994612ae72a3db9698b1d216078297b48aChris Craik        final String string = "hello ";
41baf412994612ae72a3db9698b1d216078297b48aChris Craik
42baf412994612ae72a3db9698b1d216078297b48aChris Craik        StringBuilder builder = new StringBuilder(count * string.length());
43baf412994612ae72a3db9698b1d216078297b48aChris Craik        for (int i = 0; i < count; i++) {
44baf412994612ae72a3db9698b1d216078297b48aChris Craik            builder.append(string);
45baf412994612ae72a3db9698b1d216078297b48aChris Craik        }
46baf412994612ae72a3db9698b1d216078297b48aChris Craik        sSeedText = builder.toString();
47baf412994612ae72a3db9698b1d216078297b48aChris Craik    }
48baf412994612ae72a3db9698b1d216078297b48aChris Craik
49baf412994612ae72a3db9698b1d216078297b48aChris Craik    final Object mLock = new Object();
50baf412994612ae72a3db9698b1d216078297b48aChris Craik    boolean mShouldStop = false;
51baf412994612ae72a3db9698b1d216078297b48aChris Craik
52baf412994612ae72a3db9698b1d216078297b48aChris Craik    @Override
53baf412994612ae72a3db9698b1d216078297b48aChris Craik    protected void onCreate(Bundle savedInstanceState) {
54baf412994612ae72a3db9698b1d216078297b48aChris Craik        super.onCreate(savedInstanceState);
55baf412994612ae72a3db9698b1d216078297b48aChris Craik
56baf412994612ae72a3db9698b1d216078297b48aChris Craik        EditText editText = new EditText(this);
57baf412994612ae72a3db9698b1d216078297b48aChris Craik        editText.setText(sSeedText);
58baf412994612ae72a3db9698b1d216078297b48aChris Craik        setContentView(editText);
59baf412994612ae72a3db9698b1d216078297b48aChris Craik
60baf412994612ae72a3db9698b1d216078297b48aChris Craik        final Instrumentation instrumentation = new Instrumentation();
61baf412994612ae72a3db9698b1d216078297b48aChris Craik        final Semaphore sem = new Semaphore(0);
62baf412994612ae72a3db9698b1d216078297b48aChris Craik        MessageQueue.IdleHandler handler = new MessageQueue.IdleHandler() {
63baf412994612ae72a3db9698b1d216078297b48aChris Craik            @Override
64baf412994612ae72a3db9698b1d216078297b48aChris Craik            public boolean queueIdle() {
65baf412994612ae72a3db9698b1d216078297b48aChris Craik                // TODO: consider other signaling approaches
66baf412994612ae72a3db9698b1d216078297b48aChris Craik                sem.release();
67baf412994612ae72a3db9698b1d216078297b48aChris Craik                return true;
68baf412994612ae72a3db9698b1d216078297b48aChris Craik            }
69baf412994612ae72a3db9698b1d216078297b48aChris Craik        };
70baf412994612ae72a3db9698b1d216078297b48aChris Craik        Looper.myQueue().addIdleHandler(handler);
71baf412994612ae72a3db9698b1d216078297b48aChris Craik        synchronized (mLock) {
72baf412994612ae72a3db9698b1d216078297b48aChris Craik            mShouldStop = false;
73baf412994612ae72a3db9698b1d216078297b48aChris Craik        }
74baf412994612ae72a3db9698b1d216078297b48aChris Craik        mThread = new Thread(new Runnable() {
75baf412994612ae72a3db9698b1d216078297b48aChris Craik            int codes[] = { KeyEvent.KEYCODE_H, KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_L,
76baf412994612ae72a3db9698b1d216078297b48aChris Craik                    KeyEvent.KEYCODE_L, KeyEvent.KEYCODE_O, KeyEvent.KEYCODE_SPACE };
77baf412994612ae72a3db9698b1d216078297b48aChris Craik            int i = 0;
78baf412994612ae72a3db9698b1d216078297b48aChris Craik            @Override
79baf412994612ae72a3db9698b1d216078297b48aChris Craik            public void run() {
80baf412994612ae72a3db9698b1d216078297b48aChris Craik                while (true) {
81baf412994612ae72a3db9698b1d216078297b48aChris Craik                    try {
82baf412994612ae72a3db9698b1d216078297b48aChris Craik                        sem.acquire();
83baf412994612ae72a3db9698b1d216078297b48aChris Craik                    } catch (InterruptedException e) {
84baf412994612ae72a3db9698b1d216078297b48aChris Craik                        // TODO, maybe
85baf412994612ae72a3db9698b1d216078297b48aChris Craik                    }
86baf412994612ae72a3db9698b1d216078297b48aChris Craik                    int code = codes[i % codes.length];
87baf412994612ae72a3db9698b1d216078297b48aChris Craik                    if (i % 100 == 99) code = KeyEvent.KEYCODE_ENTER;
88baf412994612ae72a3db9698b1d216078297b48aChris Craik
89baf412994612ae72a3db9698b1d216078297b48aChris Craik                    synchronized (mLock) {
90baf412994612ae72a3db9698b1d216078297b48aChris Craik                        if (mShouldStop) break;
91baf412994612ae72a3db9698b1d216078297b48aChris Craik                    }
92baf412994612ae72a3db9698b1d216078297b48aChris Craik
93baf412994612ae72a3db9698b1d216078297b48aChris Craik                    // TODO: bit of a race here, since the event can arrive after pause/stop.
94baf412994612ae72a3db9698b1d216078297b48aChris Craik                    // (Can't synchronize on key send, since it's synchronous.)
95baf412994612ae72a3db9698b1d216078297b48aChris Craik                    instrumentation.sendKeyDownUpSync(code);
96baf412994612ae72a3db9698b1d216078297b48aChris Craik                    i++;
97baf412994612ae72a3db9698b1d216078297b48aChris Craik                }
98baf412994612ae72a3db9698b1d216078297b48aChris Craik            }
99baf412994612ae72a3db9698b1d216078297b48aChris Craik        });
100baf412994612ae72a3db9698b1d216078297b48aChris Craik        mThread.start();
101baf412994612ae72a3db9698b1d216078297b48aChris Craik    }
102baf412994612ae72a3db9698b1d216078297b48aChris Craik
103baf412994612ae72a3db9698b1d216078297b48aChris Craik    @Override
104baf412994612ae72a3db9698b1d216078297b48aChris Craik    protected void onPause() {
105baf412994612ae72a3db9698b1d216078297b48aChris Craik        synchronized (mLock) {
106baf412994612ae72a3db9698b1d216078297b48aChris Craik            mShouldStop = true;
107baf412994612ae72a3db9698b1d216078297b48aChris Craik        }
108baf412994612ae72a3db9698b1d216078297b48aChris Craik        super.onPause();
109baf412994612ae72a3db9698b1d216078297b48aChris Craik    }
110baf412994612ae72a3db9698b1d216078297b48aChris Craik}
111