Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2017 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.inputmethodservice.cts;
     18 
     19 import static android.inputmethodservice.cts.common.DeviceEventConstants.ACTION_DEVICE_EVENT;
     20 import static android.inputmethodservice.cts.common.DeviceEventConstants.EXTRA_EVENT_SENDER;
     21 import static android.inputmethodservice.cts.common.DeviceEventConstants.EXTRA_EVENT_TIME;
     22 import static android.inputmethodservice.cts.common.DeviceEventConstants.EXTRA_EVENT_TYPE;
     23 import static android.inputmethodservice.cts.common.DeviceEventConstants.RECEIVER_CLASS;
     24 import static android.inputmethodservice.cts.common.DeviceEventConstants.RECEIVER_PACKAGE;
     25 
     26 import android.content.ContentValues;
     27 import android.content.Intent;
     28 import android.database.Cursor;
     29 import android.inputmethodservice.cts.common.DeviceEventConstants;
     30 import android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType;
     31 import android.inputmethodservice.cts.common.EventProviderConstants.EventTableConstants;
     32 import android.inputmethodservice.cts.common.test.TestInfo;
     33 import android.inputmethodservice.cts.db.Entity;
     34 import android.inputmethodservice.cts.db.Field;
     35 import android.inputmethodservice.cts.db.Table;
     36 import android.os.SystemClock;
     37 import android.util.Log;
     38 
     39 import androidx.annotation.NonNull;
     40 
     41 import java.util.function.Predicate;
     42 import java.util.stream.Stream;
     43 
     44 /**
     45  * Device event object.
     46  * <p>Device event is one of IME event and Test event, and is used to test behaviors of Input Method
     47  * Framework.</p>
     48  */
     49 public final class DeviceEvent {
     50 
     51     private static final boolean DEBUG_STREAM = false;
     52 
     53     public static final Table<DeviceEvent> TABLE = new DeviceEventTable(EventTableConstants.NAME);
     54 
     55     /**
     56      * Create an intent to send a device event.
     57      * @param sender an event sender.
     58      * @param type an event type defined at {@link DeviceEventType}.
     59      * @return an intent that has event {@code sender}, {@code type}, time from
     60      *         {@link SystemClock#uptimeMillis()}, and target component of event receiver.
     61      */
     62     public static Intent newDeviceEventIntent(@NonNull String sender,
     63             @NonNull DeviceEventType type) {
     64         return new Intent()
     65                 .setAction(ACTION_DEVICE_EVENT)
     66                 .setClassName(RECEIVER_PACKAGE, RECEIVER_CLASS)
     67                 .putExtra(EXTRA_EVENT_SENDER, sender)
     68                 .putExtra(EXTRA_EVENT_TYPE, type.name())
     69                 .putExtra(EXTRA_EVENT_TIME, SystemClock.uptimeMillis());
     70     }
     71 
     72     /**
     73      * Create an {@link DeviceEvent} object from an intent.
     74      * @param intent a device event intent defined at {@link DeviceEventConstants}.
     75      * @return {@link DeviceEvent} object that has event sender, type, and time form an
     76      *         {@code intent}.
     77      */
     78     public static DeviceEvent newEvent(Intent intent) {
     79         final String sender = intent.getStringExtra(EXTRA_EVENT_SENDER);
     80         if (sender == null) {
     81             throw new IllegalArgumentException(
     82                     "Intent must have " + EXTRA_EVENT_SENDER + ": " + intent);
     83         }
     84 
     85         final String typeString = intent.getStringExtra(EXTRA_EVENT_TYPE);
     86         if (typeString == null) {
     87             throw new IllegalArgumentException(
     88                     "Intent must have " + EXTRA_EVENT_TYPE + ": " + intent);
     89         }
     90         final DeviceEventType type = DeviceEventType.valueOf(typeString);
     91 
     92         if (!intent.hasExtra(EXTRA_EVENT_TIME)) {
     93             throw new IllegalArgumentException(
     94                     "Intent must have " + EXTRA_EVENT_TIME + ": " + intent);
     95         }
     96 
     97         return new DeviceEvent(sender, type, intent.getLongExtra(EXTRA_EVENT_TIME, 0L));
     98     }
     99 
    100     /**
    101      * Build {@link ContentValues} object from {@link DeviceEvent} object.
    102      * @param event a {@link DeviceEvent} object to be converted.
    103      * @return a converted {@link ContentValues} object.
    104      */
    105     public static ContentValues buildContentValues(DeviceEvent event) {
    106         return TABLE.buildContentValues(event);
    107     }
    108 
    109     /**
    110      * Build {@link Stream<DeviceEvent>} object from {@link Cursor} comes from Content Provider.
    111      * @param cursor a {@link Cursor} object to be converted.
    112      * @return a converted {@link Stream<DeviceEvent>} object.
    113      */
    114     public static Stream<DeviceEvent> buildStream(Cursor cursor) {
    115         return TABLE.buildStream(cursor);
    116     }
    117 
    118     /**
    119      * Build {@link Predicate<DeviceEvent>} whether a device event comes from {@code sender}
    120      *
    121      * @param sender event sender.
    122      * @return {@link Predicate<DeviceEvent>} object.
    123      */
    124     public static Predicate<DeviceEvent> isFrom(String sender) {
    125         return e -> e.sender.equals(sender);
    126     }
    127 
    128     /**
    129      * Build {@link Predicate<DeviceEvent>} whether a device event has an event {@code type}.
    130      *
    131      * @param type a event type defined in {@link DeviceEventType}.
    132      * @return {@link Predicate<DeviceEvent>} object.
    133      */
    134     public static Predicate<DeviceEvent> isType(DeviceEventType type) {
    135         return e -> e.type == type;
    136     }
    137 
    138     /**
    139      * Build {@link Predicate<DeviceEvent>} whether a device event is newer than or equals to
    140      * {@code time}.
    141      *
    142      * @param time a time to compare against.
    143      * @return {@link Predicate<DeviceEvent>} object.
    144      */
    145     public static Predicate<DeviceEvent> isNewerThan(long time) {
    146         return e -> e.time >= time;
    147     }
    148 
    149     /**
    150      * Event source, either Input Method class name or {@link TestInfo#getTestName()}.
    151      */
    152     @NonNull
    153     public final String sender;
    154 
    155     /**
    156      * Event type, either IME event or Test event.
    157      */
    158     @NonNull
    159     public final DeviceEventType type;
    160 
    161     /**
    162      * Event time, value is from {@link SystemClock#uptimeMillis()}.
    163      */
    164     public final long time;
    165 
    166     private DeviceEvent(String sender, DeviceEventType type, long time) {
    167         this.sender = sender;
    168         this.type = type;
    169         this.time = time;
    170     }
    171 
    172     @Override
    173     public String toString() {
    174         return "Event{ time:" + time + " type:" + type + " sender:" + sender + " }";
    175     }
    176 
    177     /**
    178      * Abstraction of device event table in database.
    179      */
    180     private static final class DeviceEventTable extends Table<DeviceEvent> {
    181 
    182         private static final String LOG_TAG = DeviceEventTable.class.getSimpleName();
    183 
    184         private final Field mSender;
    185         private final Field mType;
    186         private final Field mTime;
    187 
    188         private DeviceEventTable(String name) {
    189             super(name, new Entity.Builder<DeviceEvent>()
    190                     .addField(EventTableConstants.SENDER, Cursor.FIELD_TYPE_STRING)
    191                     .addField(EventTableConstants.TYPE, Cursor.FIELD_TYPE_STRING)
    192                     .addField(EventTableConstants.TIME, Cursor.FIELD_TYPE_INTEGER)
    193                     .build());
    194             mSender = getField(EventTableConstants.SENDER);
    195             mType = getField(EventTableConstants.TYPE);
    196             mTime = getField(EventTableConstants.TIME);
    197         }
    198 
    199         @Override
    200         public ContentValues buildContentValues(DeviceEvent event) {
    201             final ContentValues values = new ContentValues();
    202             mSender.putString(values, event.sender);
    203             mType.putString(values, event.type.name());
    204             mTime.putLong(values, event.time);
    205             return values;
    206         }
    207 
    208         @Override
    209         public Stream<DeviceEvent> buildStream(Cursor cursor) {
    210             if (DEBUG_STREAM) {
    211                 Log.d(LOG_TAG, "buildStream:");
    212             }
    213             final Stream.Builder<DeviceEvent> builder = Stream.builder();
    214             for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
    215                 final DeviceEvent event = new DeviceEvent(
    216                         mSender.getString(cursor),
    217                         DeviceEventType.valueOf(mType.getString(cursor)),
    218                         mTime.getLong(cursor));
    219                 builder.accept(event);
    220                 if (DEBUG_STREAM) {
    221                     Log.d(LOG_TAG, " event=" + event);
    222                 }
    223             }
    224             return builder.build();
    225         }
    226     }
    227 }
    228