blob: b6098f96f8d1b05a7fac218c7c3eb1e4bf8861b9 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* 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 android.inputmethodservice.cts;
import static android.inputmethodservice.cts.common.DeviceEventConstants.ACTION_DEVICE_EVENT;
import static android.inputmethodservice.cts.common.DeviceEventConstants.EXTRA_EVENT_TIME;
import static android.inputmethodservice.cts.common.DeviceEventConstants.EXTRA_EVENT_TYPE;
import static android.inputmethodservice.cts.common.DeviceEventConstants.EXTRA_EVENT_SENDER;
import static android.inputmethodservice.cts.common.DeviceEventConstants.RECEIVER_CLASS;
import static android.inputmethodservice.cts.common.DeviceEventConstants.RECEIVER_PACKAGE;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.inputmethodservice.cts.common.DeviceEventConstants;
import android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType;
import android.inputmethodservice.cts.common.EventProviderConstants.EventTableConstants;
import android.inputmethodservice.cts.common.test.TestInfo;
import android.inputmethodservice.cts.db.Entity;
import android.inputmethodservice.cts.db.Field;
import android.inputmethodservice.cts.db.Table;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.util.Log;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* Device event object.
* <p>Device event is one of IME event and Test event, and is used to test behaviors of Input Method
* Framework.</p>
*/
public final class DeviceEvent {
private static final boolean DEBUG_STREAM = false;
public static final Table<DeviceEvent> TABLE = new DeviceEventTable(EventTableConstants.NAME);
/**
* Create an intent to send a device event.
* @param sender an event sender.
* @param type an event type defined at {@link DeviceEventType}.
* @return an intent that has event {@code sender}, {@code type}, time from
* {@link SystemClock#uptimeMillis()}, and target component of event receiver.
*/
public static Intent newDeviceEventIntent(@NonNull final String sender,
@NonNull final DeviceEventType type) {
return new Intent()
.setAction(ACTION_DEVICE_EVENT)
.setClassName(RECEIVER_PACKAGE, RECEIVER_CLASS)
.putExtra(EXTRA_EVENT_SENDER, sender)
.putExtra(EXTRA_EVENT_TYPE, type.name())
.putExtra(EXTRA_EVENT_TIME, SystemClock.uptimeMillis());
}
/**
* Create an {@link DeviceEvent} object from an intent.
* @param intent a device event intent defined at {@link DeviceEventConstants}.
* @return {@link DeviceEvent} object that has event sender, type, and time form an
* {@code intent}.
*/
public static DeviceEvent newEvent(final Intent intent) {
final String sender = intent.getStringExtra(EXTRA_EVENT_SENDER);
if (sender == null) {
throw new IllegalArgumentException(
"Intent must have " + EXTRA_EVENT_SENDER + ": " + intent);
}
final String typeString = intent.getStringExtra(EXTRA_EVENT_TYPE);
if (typeString == null) {
throw new IllegalArgumentException(
"Intent must have " + EXTRA_EVENT_TYPE + ": " + intent);
}
final DeviceEventType type = DeviceEventType.valueOf(typeString);
if (!intent.hasExtra(EXTRA_EVENT_TIME)) {
throw new IllegalArgumentException(
"Intent must have " + EXTRA_EVENT_TIME + ": " + intent);
}
return new DeviceEvent(sender, type, intent.getLongExtra(EXTRA_EVENT_TIME, 0L));
}
/**
* Build {@link ContentValues} object from {@link DeviceEvent} object.
* @param event a {@link DeviceEvent} object to be converted.
* @return a converted {@link ContentValues} object.
*/
public static ContentValues buildContentValues(final DeviceEvent event) {
return TABLE.buildContentValues(event);
}
/**
* Build {@link Stream<DeviceEvent>} object from {@link Cursor} comes from Content Provider.
* @param cursor a {@link Cursor} object to be converted.
* @return a converted {@link Stream<DeviceEvent>} object.
*/
public static Stream<DeviceEvent> buildStream(final Cursor cursor) {
return TABLE.buildStream(cursor);
}
/**
* Build {@link Predicate<DeviceEvent>} whether a device event comes from {@code sender}
*
* @param sender event sender.
* @return {@link Predicate<DeviceEvent>} object.
*/
public static Predicate<DeviceEvent> isFrom(final String sender) {
return e -> e.sender.equals(sender);
}
/**
* Build {@link Predicate<DeviceEvent>} whether a device event has an event {@code type}.
*
* @param type a event type defined in {@link DeviceEventType}.
* @return {@link Predicate<DeviceEvent>} object.
*/
public static Predicate<DeviceEvent> isType(final DeviceEventType type) {
return e -> e.type == type;
}
/**
* Build {@link Predicate<DeviceEvent>} whether a device event is newer than or equals to
* {@code time}.
*
* @param time a time to compare against.
* @return {@link Predicate<DeviceEvent>} object.
*/
public static Predicate<DeviceEvent> isNewerThan(final long time) {
return e -> e.time >= time;
}
/**
* Event source, either Input Method class name or {@link TestInfo#getTestName()}.
*/
@NonNull
public final String sender;
/**
* Event type, either IME event or Test event.
*/
@NonNull
public final DeviceEventType type;
/**
* Event time, value is from {@link SystemClock#uptimeMillis()}.
*/
public final long time;
private DeviceEvent(final String sender, final DeviceEventType type, final long time) {
this.sender = sender;
this.type = type;
this.time = time;
}
@Override
public String toString() {
return "Event{ time:" + time + " type:" + type + " sender:" + sender + " }";
}
/**
* Abstraction of device event table in database.
*/
private static final class DeviceEventTable extends Table<DeviceEvent> {
private static final String LOG_TAG = DeviceEventTable.class.getSimpleName();
private final Field SENDER;
private final Field TYPE;
private final Field TIME;
private DeviceEventTable(final String name) {
super(name, new Entity.Builder<DeviceEvent>()
.addField(EventTableConstants.SENDER, Cursor.FIELD_TYPE_STRING)
.addField(EventTableConstants.TYPE, Cursor.FIELD_TYPE_STRING)
.addField(EventTableConstants.TIME, Cursor.FIELD_TYPE_INTEGER)
.build());
SENDER = getField(EventTableConstants.SENDER);
TYPE = getField(EventTableConstants.TYPE);
TIME = getField(EventTableConstants.TIME);
}
@Override
public ContentValues buildContentValues(final DeviceEvent event) {
final ContentValues values = new ContentValues();
SENDER.putString(values, event.sender);
TYPE.putString(values, event.type.name());
TIME.putLong(values, event.time);
return values;
}
@Override
public Stream<DeviceEvent> buildStream(Cursor cursor) {
if (DEBUG_STREAM) {
Log.d(LOG_TAG, "buildStream:");
}
final Stream.Builder<DeviceEvent> builder = Stream.builder();
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
final DeviceEvent event = new DeviceEvent(
SENDER.getString(cursor),
DeviceEventType.valueOf(TYPE.getString(cursor)),
TIME.getLong(cursor));
builder.accept(event);
if (DEBUG_STREAM) {
Log.d(LOG_TAG, " event=" +event);
}
}
return builder.build();
}
}
}